diff --git a/src/assets/fonts/Roboto-Condensed-Regular.woff2 b/src/assets/fonts/Roboto-Condensed-Regular.woff2 new file mode 100644 index 000000000..3bb6bd31c Binary files /dev/null and b/src/assets/fonts/Roboto-Condensed-Regular.woff2 differ diff --git a/src/assets/fonts/roboto.css b/src/assets/fonts/roboto.css index 8e64a2e07..d65175aea 100644 --- a/src/assets/fonts/roboto.css +++ b/src/assets/fonts/roboto.css @@ -151,3 +151,10 @@ src: url('Roboto-Round-Regular.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } + +@font-face { + font-family: 'Roboto Condensed'; + src: url('Roboto-Condensed-Regular.woff2') format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + diff --git a/src/components/story/MediaStory.module.scss b/src/components/story/MediaStory.module.scss index 14d79ed61..143f0df52 100644 --- a/src/components/story/MediaStory.module.scss +++ b/src/components/story/MediaStory.module.scss @@ -1,5 +1,6 @@ .root { position: relative; + overflow: hidden; } .wrapper { diff --git a/src/components/story/Story.tsx b/src/components/story/Story.tsx index b2af9dd93..0571a47a3 100644 --- a/src/components/story/Story.tsx +++ b/src/components/story/Story.tsx @@ -838,7 +838,12 @@ function Story({ )} {isLoadedStory && fullMediaData && ( - + )} {!isMobile && (
diff --git a/src/components/story/mediaArea/MediaArea.module.scss b/src/components/story/mediaArea/MediaArea.module.scss index e91df5c06..1aad3302b 100644 --- a/src/components/story/mediaArea/MediaArea.module.scss +++ b/src/components/story/mediaArea/MediaArea.module.scss @@ -114,13 +114,6 @@ } } -.withBackground { - width: 100%; - height: 100%; - background-color: var(--custom-background-color); - filter: drop-shadow(0 0.125rem 0.25rem var(--color-default-shadow)); -} - .reaction { position: absolute; top: 50%; @@ -141,26 +134,27 @@ font-weight: 500; } -.weatherInfo { - width: 100%; - height: 100%; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - transition: transform 200ms ease-out; +.weather { + display: grid; + place-items: center; +} + +.weatherInner { + width: auto !important; + height: auto !important; + display: flex; align-items: center; justify-content: center; - gap: 0.3125rem; + gap: 0.2em; white-space: nowrap; + padding: 0 0.2em; + background-color: var(--custom-background-color); + border-radius: 0.25em; } .temperature { + font-family: var(--font-family-condensed); font-weight: 700; margin: 0; } - -.border { - border-radius: 0.3125rem !important; -} diff --git a/src/components/story/mediaArea/MediaAreaOverlay.tsx b/src/components/story/mediaArea/MediaAreaOverlay.tsx index 89066d900..1cb995748 100644 --- a/src/components/story/mediaArea/MediaAreaOverlay.tsx +++ b/src/components/story/mediaArea/MediaAreaOverlay.tsx @@ -1,4 +1,6 @@ -import React, { memo, useEffect, useRef } from '../../../lib/teact/teact'; +import React, { + memo, useEffect, useRef, useState, +} from '../../../lib/teact/teact'; import { getActions } from '../../../global'; import type { ApiMediaArea, ApiStory } from '../../../api/types'; @@ -18,13 +20,15 @@ import styles from './MediaArea.module.scss'; type OwnProps = { story: ApiStory; isActive?: boolean; + isStoryPlaying?: boolean; className?: string; }; const STORY_ASPECT_RATIO = 9 / 16; +const PERCENTAGE_BASE = 100; const MediaAreaOverlay = ({ - story, isActive, className, + story, isActive, className, isStoryPlaying, }: OwnProps) => { const { openMapModal, focusMessage, closeStoryViewer, openUrl, @@ -32,12 +36,14 @@ const MediaAreaOverlay = ({ // eslint-disable-next-line no-null/no-null const ref = useRef(null); + const [mediaWidth, setMediaWidth] = useState(0); const windowSize = useWindowSize(); useEffect(() => { - if (!ref.current || !isActive) return; + if (!ref.current) return; const element = ref.current; + setMediaWidth(element!.clientWidth!); if (windowSize.width > MOBILE_SCREEN_MAX_WIDTH) { requestMutation(() => { @@ -124,8 +130,8 @@ const MediaAreaOverlay = ({ key={`${mediaArea.type}-${i}`} mediaArea={mediaArea} className={styles.mediaArea} - style={prepareStyle(mediaArea)} - isPreview={isActive} + style={prepareStyle(mediaArea, mediaWidth)} + isPreview={!isActive || isStoryPlaying} /> ); } @@ -137,18 +143,26 @@ const MediaAreaOverlay = ({ ); }; -function prepareStyle(mediaArea: ApiMediaArea) { +function prepareStyle(mediaArea: ApiMediaArea, mediaWidth?: number) { const { x, y, width, height, rotation, radius, } = mediaArea.coordinates; + let pixelRadius = ''; + + if (mediaWidth && radius && mediaWidth > 0) { + const pixelWidth = (mediaWidth * (width / PERCENTAGE_BASE)); + const pixelHeight = (mediaWidth * (height / PERCENTAGE_BASE)); + pixelRadius = `${Math.min(pixelWidth, pixelHeight) * (radius / PERCENTAGE_BASE)}px`; + } + return buildStyle( `left: ${x}%`, `top: ${y}%`, `width: ${width}%`, `height: ${height}%`, `transform: rotate(${rotation}deg) translate(-50%, -50%)`, - Boolean(radius) && `border-radius: ${radius}%`, + pixelRadius && `border-radius: ${pixelRadius}`, ); } diff --git a/src/components/story/mediaArea/MediaAreaWeather.tsx b/src/components/story/mediaArea/MediaAreaWeather.tsx index 8e53372a0..97af92b64 100644 --- a/src/components/story/mediaArea/MediaAreaWeather.tsx +++ b/src/components/story/mediaArea/MediaAreaWeather.tsx @@ -1,16 +1,19 @@ import React, { - type FC, memo, useRef, useState, + type FC, memo, + useLayoutEffect, + useRef, useState, } from '../../../lib/teact/teact'; +import { setExtraStyles } from '../../../lib/teact/teact-dom'; import { withGlobal } from '../../../global'; import type { ApiMediaAreaWeather, ApiSticker } from '../../../api/types'; +import { requestForcedReflow, requestMutation } from '../../../lib/fasterdom/fasterdom'; import { selectRestrictedEmoji } from '../../../global/selectors'; import buildClassName from '../../../util/buildClassName'; import buildStyle from '../../../util/buildStyle'; import { convertToRGBA, getTextColor } from '../../../util/colors'; import { formatTemperature } from '../../../util/formatTemperature'; -import { REM } from '../../common/helpers/mediaDimensions'; import useLastCallback from '../../../hooks/useLastCallback'; import useResizeObserver from '../../../hooks/useResizeObserver'; @@ -42,48 +45,62 @@ const MediaAreaWeather: FC = ({ }) => { // eslint-disable-next-line no-null/no-null const ref = useRef(null); - const [customEmojiSize, setCustomEmojiSize] = useState(1.5 * REM); - const [customTemperatureSize, setCustomTemperatureSize] = useState(0); + const [customEmojiSize, setCustomEmojiSize] = useState(0); const { temperatureC, color } = mediaArea; const backgroundColor = convertToRGBA(color); const textColor = getTextColor(color); - const updateCustomSize = useLastCallback(() => { - if (!ref.current) return; - const height = ref.current.clientHeight; - setCustomEmojiSize(Math.round(height * EMOJI_SIZE_MULTIPLIER)); - setCustomTemperatureSize(height / TEMPERATURE_SIZE); + const updateCustomSize = useLastCallback((isImmediate?: boolean) => { + if (!ref.current) return undefined; + const el = ref.current; + + const height = el.clientHeight; + const customEmojiHeight = Math.round(height * EMOJI_SIZE_MULTIPLIER); + setCustomEmojiSize(customEmojiHeight); + const applyFn = () => { + setExtraStyles(el, { + '--custom-emoji-size': `${customEmojiHeight}px`, + 'font-size': `${height / TEMPERATURE_SIZE}rem`, + }); + }; + + if (isImmediate) return applyFn; + + requestMutation(applyFn); + + return undefined; }); - useResizeObserver(ref, updateCustomSize); + useLayoutEffect(() => { + requestForcedReflow(() => updateCustomSize(true)); + }, []); + + useResizeObserver(ref, () => updateCustomSize()); return (
-
+
{restrictedEmoji && ( )} -

+

{formatTemperature(temperatureC)}

diff --git a/src/styles/index.scss b/src/styles/index.scss index 18a22766f..38eae501a 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -30,10 +30,11 @@ body { user-select: none; --font-family: "Roboto", -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI", Oxygen, Ubuntu, - Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; --font-family-monospace: "Cascadia Mono", "Roboto Mono", "Droid Sans Mono", 'SF Mono', "Menlo", "Ubuntu Mono", - "Consolas", monospace; + "Consolas", monospace; --font-family-rounded: -ui-rounded, "Roboto Round"; + --font-family-condensed: -ui-rounded, "Roboto Condensed"; @media (max-width: 600px) { height: calc(var(--vh, 1vh) * 100); @@ -61,18 +62,18 @@ html.theme-dark { body.is-ios, body.is-macos { --font-family: system-ui, -apple-system, BlinkMacSystemFont, "Roboto", "Apple Color Emoji", "Helvetica Neue", - sans-serif; + sans-serif; } html[lang="fa"], html[lang="fa"] body { --font-family: "Vazirmatn", "Roboto", -apple-system, BlinkMacSystemFont, "Apple Color Emoji", "Segoe UI", Oxygen, - Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; &.is-ios, &.is-macos { --font-family: "Vazirmatn", -apple-system, BlinkMacSystemFont, "Roboto", "Apple Color Emoji", "Segoe UI", Oxygen, - Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; } } diff --git a/src/util/formatTemperature.ts b/src/util/formatTemperature.ts index 6c1fa6505..1d949838c 100644 --- a/src/util/formatTemperature.ts +++ b/src/util/formatTemperature.ts @@ -1,4 +1,4 @@ export const formatTemperature = (temperatureC: number) => { const isFahrenheit = Boolean(navigator.language === 'en-US'); - return isFahrenheit ? `${Math.round((temperatureC * 9) / 5 + 32)} °F` : `${Math.round(temperatureC)} °C`; + return isFahrenheit ? `${Math.round((temperatureC * 9) / 5 + 32)}°F` : `${Math.round(temperatureC)}°C`; };