feat: improve scaling in portrait mobile. Add close button for mobile chat (#157)

This commit is contained in:
Vitaly 2024-07-08 03:49:10 +03:00 committed by GitHub
commit 0a6fa7d7b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 88 additions and 63 deletions

View file

@ -2,8 +2,9 @@ import React from 'react'
import type { Preview } from "@storybook/react"
import '../src/styles.css'
import './storybook.css'
import '../src/styles.css'
import '../src/scaleInterface'
const preview: Preview = {
decorators: [

View file

@ -4,10 +4,15 @@ export default async ({ tokenCaches, proxyBaseUrl, setProgressText = (text) => {
// const sessionEndpoint = 'http://localhost:3000/session'
let authEndpoint = ''
let sessionEndpoint = ''
if (!proxyBaseUrl.startsWith('http')) proxyBaseUrl = `${isPageSecure() ? 'https' : 'http'}://${proxyBaseUrl}`
const url = proxyBaseUrl + '/api/vm/net/connect'
let result: Response
try {
result = await fetch(url)
} catch (err) {
throw new Error(`Selected proxy server ${proxyBaseUrl} most likely is down`)
}
try {
if (!proxyBaseUrl.startsWith('http')) proxyBaseUrl = `${isPageSecure() ? 'https' : 'http'}://${proxyBaseUrl}`
const url = proxyBaseUrl + '/api/vm/net/connect'
const result = await fetch(url)
const json = await result.json()
authEndpoint = urlWithBase(json.capabilities.authEndpoint, proxyBaseUrl)
sessionEndpoint = urlWithBase(json.capabilities.sessionEndpoint, proxyBaseUrl)

View file

@ -28,6 +28,7 @@ export default ({ status, isError, hideDots = false, lastStatus = '', backAction
return (
<Screen
className='small-content'
title={
<>
<span style={{ userSelect: isError ? 'text' : undefined }}>

View file

@ -24,6 +24,13 @@ div.chat-wrapper {
left: 1px;
box-sizing: border-box;
background-color: rgba(0, 0, 0, 0);
display: flex;
align-items: center;
gap: 1px;
}
.chat-input-wrapper form {
display: flex;
}
.chat-input {
@ -103,7 +110,8 @@ div.chat-wrapper {
}
.input-mobile #chatinput {
height: 20px;
height: 24px;
font-size: 13px;
}
.display-mobile {

View file

@ -4,6 +4,8 @@ import { MessageFormatPart } from '../botUtils'
import { MessagePart } from './MessageFormatted'
import './Chat.css'
import { isIos, reactKeyForMessage } from './utils'
import Button from './Button'
import { pixelartIcons } from './PixelartIcon'
export type Message = {
parts: MessageFormatPart[],
@ -221,6 +223,8 @@ export default ({
</div>
<div className={`chat-wrapper chat-input-wrapper ${usingTouch ? 'input-mobile' : ''}`} hidden={!opened}>
{/* close button */}
{usingTouch && <Button icon={pixelartIcons.close} onClick={() => onClose?.()} />}
<div className="chat-input">
{completionItems?.length ? (
<div className="chat-completions">
@ -307,6 +311,7 @@ export default ({
onFocus={() => auxInputFocus('ArrowDown')}
onChange={() => { }}
/>}
{/* for some reason this is needed to make Enter work on android chrome */}
<button type='submit' style={{ visibility: 'hidden' }} />
</form>
</div>

View file

@ -1,6 +1,11 @@
import { useEffect, useState } from 'react'
import { useSnapshot } from 'valtio'
import { activeModalStack, miscUiState } from '../globalState'
import Button from './Button'
import { useUsingTouch } from './utilsApp'
import { pixelartIcons } from './PixelartIcon'
const hideOnModals = new Set(['chat'])
export default () => {
const [fullScreen, setFullScreen] = useState(false)
@ -9,16 +14,23 @@ export default () => {
setFullScreen(!!document.fullscreenElement)
})
}, [])
const { gameLoaded } = useSnapshot(miscUiState)
const activeStack = useSnapshot(activeModalStack)
const inMainMenu = activeStack.length === 0 && !gameLoaded
const usingTouch = useUsingTouch()
if (!usingTouch || !document.documentElement.requestFullscreen || fullScreen) return null
const hideButton = activeStack.some(x => hideOnModals.has(x.reactType))
if (hideButton || !usingTouch || !document.documentElement.requestFullscreen || fullScreen) return null
return <Button
icon='pixelarticons:scale'
icon={pixelartIcons.scale}
style={{
position: 'fixed',
top: 5,
left: 5,
left: inMainMenu ? 35 : 5,
width: 22,
}}
onClick={() => {

View file

@ -349,19 +349,20 @@ export const ButtonWithMatchesAlert = ({
}
export const AwaitingInputOverlay = ({ isGamepad }) => {
return <div style={{
position: 'fixed',
inset: 0,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'column',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
color: 'white',
fontSize: 20,
zIndex: 10,
textAlign: 'center',
}}
return <div
style={{
position: 'fixed',
inset: 0,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'column',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
color: 'white',
fontSize: 20,
zIndex: 10,
textAlign: 'center',
}}
onContextMenu={e => e.preventDefault()}
>
<div>

View file

@ -3,13 +3,14 @@ interface Props {
children: React.ReactNode
backdrop?: boolean | 'dirt'
style?: React.CSSProperties
className?: string
}
export default ({ title, children, backdrop = true, style }: Props) => {
export default ({ title, children, backdrop = true, style, className }: Props) => {
return (
<>
{backdrop === 'dirt' ? <div className='dirt-bg'></div> : backdrop ? <div className="backdrop"></div> : null}
<div className='fullscreen' style={{ overflow: 'auto', ...style }}>
<div className={`fullscreen ${className}`} style={{ overflow: 'auto', ...style }}>
<div className="screen-content">
<div className="screen-title">{title}</div>
{children}

View file

@ -104,7 +104,7 @@
padding-right: calc(env(safe-area-inset-right) / 2);
}
@media only screen and (max-height: 313px) {
@media only screen and (max-height: 420px) {
.root {
--top-offset: 10px
}

View file

@ -1,5 +1,6 @@
import { useSnapshot } from 'valtio'
import { useEffect, useMemo } from 'react'
import { useMedia } from 'react-use'
import { activeModalStack, miscUiState } from '../globalState'
export const watchedModalsFromHooks = new Set<string>()
@ -28,3 +29,7 @@ export const useIsModalActive = (modal: string, useIncludes = false) => {
export const useIsWidgetActive = (name: string) => {
return useIsModalActive(`widget-${name}`)
}
export const useIsSmallWidth = () => {
return useMedia('(max-width: 550px)')
}

View file

@ -1,31 +1,37 @@
import { proxy } from 'valtio'
import { subscribeKey } from 'valtio/utils'
import { options } from './optionsStorage'
import { options, watchValue } from './optionsStorage'
export const currentScaling = proxy({
scale: 1,
})
window.currentScaling = currentScaling
const setScale = () => {
const scaleValues = [
{ width: 971, height: 670, scale: 2 },
{ width: null, height: 430, scale: 1.5 },
{ width: 590, height: null, scale: 1 }
{ maxWidth: 971, maxHeight: 670, scale: 2 },
{ maxWidth: null, maxHeight: 390, scale: 1.5 }, // todo allow to set the scaling at 360-400 (dynamic scaling setting)
{ maxWidth: 590, maxHeight: null, scale: 1 },
{ maxWidth: 590, minHeight: 240, scale: 1.4 },
]
const { innerWidth, innerHeight } = window
let result = options.guiScale
for (const { width, height, scale } of scaleValues) {
if ((width && innerWidth <= width) || (height && innerHeight <= height)) {
for (const { maxWidth, maxHeight, scale, minHeight } of scaleValues) {
if ((!maxWidth || innerWidth <= maxWidth) && (!maxHeight || innerHeight <= maxHeight) && (!minHeight || innerHeight >= minHeight)) {
result = scale
}
}
currentScaling.scale = result
document.documentElement.style.setProperty('--guiScale', String(result))
}
setScale()
subscribeKey(options, 'guiScale', setScale)
watchValue(currentScaling, (c) => {
document.documentElement.style.setProperty('--guiScale', String(c.scale))
})
window.addEventListener('resize', setScale)

View file

@ -41,6 +41,18 @@
gap: 10px;
}
@media screen and (max-height: 426px) {
.fullscreen:not(.small-content) {
.screen-content {
margin-top: 14px;
}
.screen-title {
margin-bottom: 5px;
}
}
}
.screen-items {
display: grid;
grid-template-columns: repeat(2, 1fr);

View file

@ -199,35 +199,3 @@ body::xr-overlay #viewer-canvas {
opacity: 1;
}
}
@media only screen and (max-width: 971px) {
#ui-root {
transform: scale(2);
width: calc(100% / 2);
height: calc(100% / 2);
}
}
@media only screen and (max-height: 670px) {
#ui-root {
transform: scale(2);
width: calc(100% / 2);
height: calc(100% / 2);
}
}
@media only screen and (max-width: 590px) {
#ui-root {
transform: scale(1);
width: calc(100% / 1);
height: calc(100% / 1);
}
}
@media only screen and (max-height: 430px) {
#ui-root {
transform: scale(1.5);
width: calc(100% / 1.5);
height: calc(100% / 1.5);
}
}