improve mobile mode

This commit is contained in:
SrGooglo 2023-06-09 14:26:01 +00:00
parent 163cf09eab
commit c7a554e455
34 changed files with 545 additions and 368 deletions

View File

@ -88,7 +88,7 @@ import { DOMWindow } from "components/RenderWindow"
import { Icons } from "components/Icons" import { Icons } from "components/Icons"
import { ThemeProvider } from "cores/style" import { ThemeProvider } from "cores/style/style.core.jsx"
import Layout from "./layout" import Layout from "./layout"
import * as Router from "./router" import * as Router from "./router"

View File

@ -74,7 +74,7 @@ export default class Drawer extends Component {
ALLOW_DRAWER_TRANSFORM = true ALLOW_DRAWER_TRANSFORM = true
componentDidMount() { componentDidMount() {
this.DESKTOP_MODE = !window.isMobile this.DESKTOP_MODE = !app.isMobile
} }
componentDidUpdate(prevProps, nextState) { componentDidUpdate(prevProps, nextState) {

View File

@ -6,31 +6,39 @@ import { Motion, spring } from "react-motion"
import { Icons, createIconRender } from "components/Icons" import { Icons, createIconRender } from "components/Icons"
import { WithPlayerContext, Context } from "contexts/WithPlayerContext"
import PlayerView from "pages/@mobile-views/player"
import "./index.less" import "./index.less"
const items = [ const PlayerButton = (props) => {
{ const openPlayerView = () => {
id: "creator", app.DrawerController.open("player", PlayerView)
dispatchEvent: "app.openCreator",
icon: "PlusCircle",
classnames: [["primary"]]
},
{
id: "feed",
location: "/home/feed",
icon: "Home",
},
{
id: "explore",
location: "/home/explore",
icon: "Search",
},
{
id: "livestreams",
location: "/home/livestreams",
icon: "Tv",
} }
]
React.useEffect(() => {
openPlayerView()
}, [])
return <div
className={classnames(
"player_btn",
{
"bounce": props.playback === "playing"
}
)}
style={{
"--average-color": props.colorAnalysis?.rgba,
"--color": props.colorAnalysis?.isDark ? "var(--text-color-white)" : "var(--text-color-black)",
}}
onClick={openPlayerView}
>
{
props.playback === "playing" ? <Icons.MdMusicNote /> : <Icons.MdPause />
}
</div>
}
const AccountButton = (props) => { const AccountButton = (props) => {
const user = app.userData const user = app.userData
@ -51,26 +59,10 @@ const AccountButton = (props) => {
key: "settings", key: "settings",
text: <><Icons.Settings /> <span>Settings</span></>, text: <><Icons.Settings /> <span>Settings</span></>,
onClick: () => { onClick: () => {
app.openSettings() app.navigation.goToSettings()
ActionSheetRef.current.close() ActionSheetRef.current.close()
} }
}, },
{
key: "savedPosts",
text: <><Icons.Bookmark /> <span>Saved Posts</span></>,
onClick: () => {
app.setLocation("/home/savedPosts")
ActionSheetRef.current.close()
}
},
{
key: "about",
text: <><Icons.Info /> <span>About</span></>,
onClick: () => {
app.setLocation("/about")
ActionSheetRef.current.close()
}
}
] ]
}) })
} }
@ -91,7 +83,17 @@ const AccountButton = (props) => {
</div> </div>
} }
export default class BottomBar extends React.Component { export default (props) => {
return <WithPlayerContext>
<BottomBar
{...props}
/>
</WithPlayerContext>
}
export class BottomBar extends React.Component {
static contextType = Context
state = { state = {
allowed: true, allowed: true,
show: true, show: true,
@ -133,7 +135,7 @@ export default class BottomBar extends React.Component {
} }
toggleVisibility = (to) => { toggleVisibility = (to) => {
if (!window.isMobile) { if (!app.isMobile) {
to = false to = false
} else { } else {
to = to ?? !this.state.visible to = to ?? !this.state.visible
@ -160,21 +162,6 @@ export default class BottomBar extends React.Component {
} }
} }
renderItems = () => {
return items.map((item) => {
return <div
key={item.id}
id={item.id}
className={classnames("item", ...item.classnames ?? [])}
onClick={() => this.handleItemClick(item)}
>
<div className="icon">
{createIconRender(item.icon)}
</div>
</div>
})
}
render() { render() {
if (this.state.render) { if (this.state.render) {
return <div className="bottomBar"> return <div className="bottomBar">
@ -195,7 +182,51 @@ export default class BottomBar extends React.Component {
}} }}
> >
<div className="items"> <div className="items">
{this.renderItems()} <div
key="creator"
id="creator"
className={classnames("item", "primary")}
onClick={() => app.setLocation("/")}
>
<div className="icon">
{createIconRender("PlusCircle")}
</div>
</div>
{
this.context.currentManifest && <div
className="item"
>
<PlayerButton
manifest={this.context.currentManifest}
playback={this.context.playbackStatus}
colorAnalysis={this.context.coverColorAnalysis}
/>
</div>
}
<div
key="navigator"
id="navigator"
className="item"
onClick={() => app.setLocation("/")}
>
<div className="icon">
{createIconRender("Home")}
</div>
</div>
<div
key="searcher"
id="searcher"
className="item"
onClick={app.controls.openSearcher}
>
<div className="icon">
{createIconRender("Search")}
</div>
</div>
<AccountButton /> <AccountButton />
</div> </div>
</div>} </div>}

View File

@ -1,4 +1,26 @@
@import "theme/vars.less"; @import "theme/vars.less";
@import "theme/animations.less";
.player_btn {
color: var(--color);
background-color: var(--average-color);
padding: 10px 20px;
border-radius: 8px;
&.bounce {
svg {
animation: bounce 1s infinite;
}
}
svg {
color: var(--color);
margin: 0;
}
}
.bottomBar { .bottomBar {
display: flex; display: flex;
@ -24,6 +46,8 @@
background-color: var(--background-color-accent); background-color: var(--background-color-accent);
border-radius: 12px 12px 0 0; border-radius: 12px 12px 0 0;
box-shadow: @card-shadow;
.items { .items {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;

View File

@ -227,7 +227,7 @@ export default class Login extends React.Component {
> >
<span><Icons.Lock /> Password</span> <span><Icons.Lock /> Password</span>
<antd.Input.Password <antd.Input.Password
placeholder="********" //placeholder="********"
onChange={(e) => this.onUpdateInput("password", e.target.value)} onChange={(e) => this.onUpdateInput("password", e.target.value)}
onPressEnter={this.nextStep} onPressEnter={this.nextStep}
/> />

View File

@ -0,0 +1,59 @@
import React from "react"
import classnames from "classnames"
import * as antd from "antd"
import { createIconRender } from "components/Icons"
import "./index.less"
const NavMenu = (props) => {
const handleOnClickItem = (event) => {
return props.onClickItem(event.key)
}
return <div className="navmenu_wrapper">
{
props.header && <div className="card header" id="navMenu">
{props.header}
</div>
}
<div className="card content" id="navMenu">
<antd.Menu
mode="inline"
selectedKeys={[props.activeKey]}
onClick={handleOnClickItem}
items={props.items}
/>
</div>
</div>
}
const NavMenuMobile = (props) => {
return <div className="__mobile__navmenu_wrapper">
<div className="card">
{
props.items.map((item) => {
return <div
key={item.key}
className={classnames(
"item",
item.key === props.activeKey && "active",
)}
onClick={() => props.onClickItem(item.key)}
>
<div className="icon">
{item.icon}
</div>
<div className="label">
{item.label}
</div>
</div>
})
}
</div>
</div>
}
export default app.isMobile ? NavMenuMobile : NavMenu

View File

@ -0,0 +1,21 @@
.navmenu_wrapper {
position: relative;
}
.__mobile__navmenu_wrapper {
box-sizing: border-box;
position: sticky;
top: 0;
left: 0;
width: 100%;
.card {
display: flex;
flex-direction: row;
gap: 10px;
}
}

View File

@ -4,6 +4,8 @@ import * as antd from "antd"
import { createIconRender } from "components/Icons" import { createIconRender } from "components/Icons"
import NavMenu from "./components/NavMenu"
import "./index.less" import "./index.less"
export const Panel = (props) => { export const Panel = (props) => {
@ -19,29 +21,6 @@ export const Panel = (props) => {
</div> </div>
} }
const NavMenu = (props) => {
const handleOnClickItem = (event) => {
return props.onClickItem(event.key)
}
return <div className="navmenu_wrapper">
{
props.header && <div className="card header" id="navMenu">
{props.header}
</div>
}
<div className="card content" id="navMenu">
<antd.Menu
mode="inline"
selectedKeys={[props.activeKey]}
onClick={handleOnClickItem}
items={props.items}
/>
</div>
</div>
}
export class PagePanelWithNavMenu extends React.Component { export class PagePanelWithNavMenu extends React.Component {
state = { state = {
// if defaultTab is not set, try to get it from query, if not, use the first tab // if defaultTab is not set, try to get it from query, if not, use the first tab

View File

@ -1,3 +1,5 @@
@import "theme/animations.less";
.background_media_player { .background_media_player {
position: relative; position: relative;
@ -234,23 +236,4 @@
} }
} }
} }
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-5px);
}
60% {
transform: translateY(-3px);
}
} }

View File

@ -79,23 +79,25 @@ export default ({
onClick={() => onClickActionsButton("next")} onClick={() => onClickActionsButton("next")}
disabled={syncModeLocked} disabled={syncModeLocked}
/> />
<antd.Popover {
content={React.createElement( !app.isMobile && <antd.Popover
AudioVolume, content={React.createElement(
{ onChange: onVolumeUpdate, defaultValue: audioVolume } AudioVolume,
)} { onChange: onVolumeUpdate, defaultValue: audioVolume }
trigger="hover" )}
> trigger="hover"
<div
className="muteButton"
onClick={onMuteUpdate}
> >
{ <div
audioMuted className="muteButton"
? <Icons.VolumeX /> onClick={onMuteUpdate}
: <Icons.Volume2 /> >
} {
</div> audioMuted
</antd.Popover> ? <Icons.VolumeX />
: <Icons.Volume2 />
}
</div>
</antd.Popover>
}
</div> </div>
} }

View File

@ -90,8 +90,9 @@ export class AudioPlayer extends React.Component {
className={classnames( className={classnames(
"embbededMediaPlayerWrapper", "embbededMediaPlayerWrapper",
{ {
["hovering"]: this.state.showControls, ["hovering"]: this.props.frame !== false && this.state.showControls,
["minimized"]: this.context.minimized, ["minimized"]: this.context.minimized,
["no-frame"]: this.props.frame === false,
} }
)} )}
onMouseEnter={this.onMouse} onMouseEnter={this.onMouse}

View File

@ -18,6 +18,31 @@
transition: all 150ms ease-in-out; transition: all 150ms ease-in-out;
&.no-frame {
width: 100%;
height: 100%;
flex-direction: column;
.player {
background-color: transparent;
border-radius: 0;
box-shadow: none;
}
.top_controls {
position: relative;
opacity: 1;
height: @top_controls_height;
width: 100%;
background-color: transparent;
box-shadow: none;
}
}
&.minimized { &.minimized {
pointer-events: none; pointer-events: none;

View File

@ -98,10 +98,14 @@
font-size: 0.9rem; font-size: 0.9rem;
color: var(--text-color);
.playlistTimelineEntry_statistic { .playlistTimelineEntry_statistic {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
color: var(--text-color);
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }

View File

@ -5,7 +5,7 @@
width: 35vw; width: 35vw;
min-width: 300px; min-width: 300px;
max-width: 800px; max-width: 800px;
//max-width: 600px; //max-width: 600px;
//min-height: 165px; //min-height: 165px;
//height: 100%; //height: 100%;

View File

@ -368,95 +368,43 @@ export class PostsListsComponent extends React.Component {
return <div className="post-list_wrapper"> return <div className="post-list_wrapper">
<LoadMore <LoadMore
ref={this.listRef} ref={this.listRef}
className="post-list" className="post-list"
loadingComponent={LoadingComponent} loadingComponent={LoadingComponent}
noResultComponent={NoResultComponent} noResultComponent={NoResultComponent}
hasMore={this.state.hasMore} hasMore={this.state.hasMore}
fetching={this.state.loading} fetching={this.state.loading}
onBottom={this.onLoadMore} onBottom={this.onLoadMore}
> >
{ {
!this.state.realtimeUpdates && <div className="resume_btn_wrapper"> !this.state.realtimeUpdates && !app.isMobile && <div className="resume_btn_wrapper">
<antd.Button <antd.Button
type="primary" type="primary"
shape="round" shape="round"
onClick={this.onResumeRealtimeUpdates} onClick={this.onResumeRealtimeUpdates}
loading={this.state.resumingLoading} loading={this.state.resumingLoading}
icon={<Icons.SyncOutlined />} icon={<Icons.SyncOutlined />}
> >
Resume Resume
</antd.Button> </antd.Button>
</div> </div>
} }
{ {
this.state.list.map((data) => { this.state.list.map((data) => {
return React.createElement(typeToComponent[data.type ?? "post"] ?? PostCard, { return React.createElement(typeToComponent[data.type ?? "post"] ?? PostCard, {
key: data._id, key: data._id,
data: data, data: data,
events: { events: {
onClickLike: this.onLikePost, onClickLike: this.onLikePost,
onClickSave: this.onSavePost, onClickSave: this.onSavePost,
onClickDelete: this.onDeletePost, onClickDelete: this.onDeletePost,
onClickEdit: this.onEditPost, onClickEdit: this.onEditPost,
} }
})
})
}
</LoadMore>
</div>
return <AutoSizer
disableWidth
style={{
width: "100%",
}}
>
{({ height }) => {
console.log("[PostList] AutoSizer height update => ", height)
return <LoadMore
ref={this.listRef}
contentProps={{
style: { height }
}}
className="postList"
loadingComponent={LoadingComponent}
noResultComponent={NoResultComponent}
hasMore={this.state.hasMore}
fetching={this.state.loading}
onBottom={this.onLoadMore}
>
{
!this.state.realtimeUpdates && <div className="resume_btn_wrapper">
<antd.Button
type="primary"
shape="round"
onClick={this.onResumeRealtimeUpdates}
loading={this.state.resumingLoading}
icon={<Icons.SyncOutlined />}
>
Resume
</antd.Button>
</div>
}
{
this.state.list.map((data) => {
return React.createElement(typeToComponent[data.type ?? "post"] ?? PostCard, {
key: data._id,
data: data,
events: {
onClickLike: this.onLikePost,
onClickSave: this.onSavePost,
onClickDelete: this.onDeletePost,
onClickEdit: this.onEditPost,
}
})
}) })
} })
</LoadMore> }
}} </LoadMore>
</AutoSizer> </div>
} }
} }

View File

@ -33,7 +33,6 @@
margin: auto; margin: auto;
z-index: 150; z-index: 150;
} }
.resume_btn_wrapper { .resume_btn_wrapper {

View File

@ -51,12 +51,8 @@ export default class Layout extends React.PureComponent {
} }
componentDidMount() { componentDidMount() {
if (window.app.cores.settings.get("forceMobileMode") || window.app.capacitor.isAppCapacitor() || Math.min(window.screen.width, window.screen.height) < 768 || navigator.userAgent.indexOf("Mobi") > -1) { if (window.app.cores.settings.get("forceMobileMode") || app.isMobile) {
window.isMobile = true
app.layout.set("mobile") app.layout.set("mobile")
} else {
window.isMobile = false
} }
// register events // register events
@ -147,7 +143,7 @@ export default class Layout extends React.PureComponent {
return JSON.stringify(this.state.renderError) return JSON.stringify(this.state.renderError)
} }
const Layout = Layouts[layoutType] const Layout = Layouts[app.isMobile ? "mobile" : layoutType]
if (!Layout) { if (!Layout) {
return app.eventBus.emit("runtime.crash", new Error(`Layout type [${layoutType}] not found`)) return app.eventBus.emit("runtime.crash", new Error(`Layout type [${layoutType}] not found`))

View File

@ -9,11 +9,9 @@ export default (props) => {
<Modal /> <Modal />
<antd.Layout.Content className={classnames("content_layout", ...props.layoutPageModesClassnames ?? [])}> <antd.Layout.Content className={classnames("content_layout", ...props.layoutPageModesClassnames ?? [])}>
<div className={classnames("frameDecorator", "top")} />
<div id="transitionLayer" className={classnames("content_wrapper", "fade-transverse-active")}> <div id="transitionLayer" className={classnames("content_wrapper", "fade-transverse-active")}>
{React.cloneElement(props.children, props)} {React.cloneElement(props.children, props)}
</div> </div>
<div className={classnames("frameDecorator", "bottom")} />
</antd.Layout.Content> </antd.Layout.Content>
<BottomBar /> <BottomBar />

View File

@ -5,7 +5,7 @@ import classnames from "classnames"
import { Drawer, Sidedrawer } from "components/Layout" import { Drawer, Sidedrawer } from "components/Layout"
export default (props) => { export default (props) => {
return <antd.Layout className={classnames("app_layout", { ["mobile"]: window.isMobile })} style={{ height: "100%" }}> return <antd.Layout className={classnames("app_layout", { ["mobile"]: app.isMobile })} style={{ height: "100%" }}>
<Drawer /> <Drawer />
<Sidedrawer /> <Sidedrawer />
<div id="transitionLayer" className="fade-transverse-active"> <div id="transitionLayer" className="fade-transverse-active">

View File

@ -0,0 +1,12 @@
import React from "react"
import MediaPlayer from "components/Player/MediaPlayer"
import "./index.less"
export default () => {
return <div className="__mobile-player-view">
<MediaPlayer
frame={false}
/>
</div>
}

View File

@ -0,0 +1,8 @@
.__mobile-player-view {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}

View File

@ -258,7 +258,7 @@ export default class Account extends React.Component {
<div className="tabMenuWrapper"> <div className="tabMenuWrapper">
<antd.Menu <antd.Menu
className="tabMenu" className="tabMenu"
mode={window.isMobile ? "horizontal" : "vertical"} mode={app.isMobile ? "horizontal" : "vertical"}
selectedKeys={[this.state.tabActiveKey]} selectedKeys={[this.state.tabActiveKey]}
onClick={(e) => this.handlePageTransition(e.key)} onClick={(e) => this.handlePageTransition(e.key)}
> >

View File

@ -0,0 +1,35 @@
import React from "react"
import * as antd from "antd"
import { Translation } from "react-i18next"
import { PagePanelWithNavMenu } from "components/PagePanels"
import { Icons } from "components/Icons"
import Tabs from "./home/tabs"
export default class Home extends React.Component {
render() {
const navMenuHeader = <>
<h1>
<Icons.Home />
<Translation>{(t) => t("Timeline")}</Translation>
</h1>
<antd.Button
type="primary"
onClick={app.controls.openPostCreator}
>
<Icons.PlusCircle />
<Translation>{(t) => t("Create")}</Translation>
</antd.Button>
</>
return <PagePanelWithNavMenu
tabs={Tabs}
navMenuHeader={navMenuHeader}
primaryPanelClassName="full"
useSetQueryType
transition
/>
}
}

View File

@ -75,7 +75,7 @@ export default (props) => {
<div className="content"> <div className="content">
<div className="content_header"> <div className="content_header">
<img src={window.isMobile ? config.logo.alt : config.logo.full} className="logo" /> <img src={app.isMobile ? config.logo.alt : config.logo.full} className="logo" />
</div> </div>
{ {

View File

@ -1,12 +1,15 @@
import React from "react" import React from "react"
import "./index.less" import "./index.mobile.less"
export default (props) => { export default (props) => {
const [wallpaperData, setWallpaperData] = React.useState(null) const [wallpaperData, setWallpaperData] = React.useState(null)
const setRandomWallpaper = async () => { const setRandomWallpaper = async () => {
const featuredWallpapers = await app.cores.api.request("main", "get", "featuredWallpapers").catch((err) => { const { data: featuredWallpapers } = await app.cores.api.customRequest({
method: "GET",
url: "/featured_wallpapers"
}).catch((err) => {
console.error(err) console.error(err)
return [] return []
}) })
@ -19,12 +22,12 @@ export default (props) => {
React.useEffect(() => { React.useEffect(() => {
if (app.userData) { if (app.userData) {
return app.goMain() return app.navigation.goMain()
} }
setRandomWallpaper() setRandomWallpaper()
app.eventBus.emit("app.createLogin", { app.controls.openLoginForm({
defaultLocked: true, defaultLocked: true,
}) })
}, []) }, [])
@ -36,9 +39,9 @@ export default (props) => {
}} }}
className="wallpaper" className="wallpaper"
> >
<p> {/* <p>
{wallpaperData?.author ? wallpaperData.author : null} {wallpaperData?.author ? wallpaperData.author : null}
</p> </p> */}
</div> </div>
</div> </div>
} }

View File

@ -0,0 +1,22 @@
.loginPage {
position: relative;
width: 100%;
height: 100vh;
height: 100dvh;
.wallpaper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
height: 100dvh;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
}

View File

@ -601,10 +601,16 @@ export default class SyncLyrics extends React.Component {
colorAnalysis, colorAnalysis,
}) })
app.SidebarController.toggleVisibility(false) if (app.SidebarController) {
app.SidebarController.toggleVisibility(false)
}
if (app.layout.floatingStack) {
app.layout.floatingStack.toogleGlobalVisibility(false)
}
app.cores.style.compactMode(true) app.cores.style.compactMode(true)
app.cores.style.applyVariant("dark") app.cores.style.applyVariant("dark")
app.layout.floatingStack.toogleGlobalVisibility(false)
// request full screen to browser // request full screen to browser
if (document.fullscreenEnabled) { if (document.fullscreenEnabled) {
@ -640,10 +646,16 @@ export default class SyncLyrics extends React.Component {
delete window._hacks delete window._hacks
app.SidebarController.toggleVisibility(true) if (app.SidebarController) {
app.SidebarController.toggleVisibility(true)
}
if (app.layout.floatingStack) {
app.layout.floatingStack.toogleGlobalVisibility(true)
}
app.cores.style.compactMode(false) app.cores.style.compactMode(false)
app.cores.style.applyInitialVariant() app.cores.style.applyInitialVariant()
app.layout.floatingStack.toogleGlobalVisibility(true)
// exit full screen // exit full screen
if (document.fullscreenEnabled) { if (document.fullscreenEnabled) {

View File

@ -279,7 +279,9 @@ export default class PlaylistCreatorSteps extends React.Component {
okType: "danger", okType: "danger",
cancelText: "Cancel", cancelText: "Cancel",
onOk: async () => { onOk: async () => {
const result = await PlaylistModel.deletePlaylist(this.props.playlist_id) const result = await PlaylistModel.deletePlaylist(this.props.playlist_id, {
remove_with_tracks: true
})
if (result) { if (result) {
app.message.success("Playlist deleted") app.message.success("Playlist deleted")

View File

@ -105,7 +105,7 @@ export default (props) => {
return <div return <div
className={ className={
classnames("play", playlist.type) classnames("playlist_view", playlist.type)
} }
> >
<div className="play_info_wrapper"> <div className="play_info_wrapper">

View File

@ -1,4 +1,4 @@
.play { .playlist_view {
display: grid; display: grid;
grid-template-columns: 30vw 1fr; grid-template-columns: 30vw 1fr;
@ -54,15 +54,12 @@
background-color: black; background-color: black;
border-radius: 12px; border-radius: 12px;
overflow: hidden; overflow: hidden;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 12px;
object-fit: cover; object-fit: cover;
} }
} }

View File

@ -591,7 +591,7 @@ export default () => {
className={classnames( className={classnames(
"settings_wrapper", "settings_wrapper",
{ {
["mobile"]: window.isMobile, ["mobile"]: app.isMobile,
} }
)} )}
> >

View File

@ -46,7 +46,7 @@ const mobileRoutes = Object.keys(pathsMobile).map((route) => {
return { return {
path, path,
element: pathsMobile[path] element: pathsMobile[route]
} }
}) })
@ -192,13 +192,11 @@ export const PageRender = React.memo((props) => {
return <Routes> return <Routes>
{ {
routes.map((route, index) => { routes.map((route, index) => {
let Element = route.element if (app.isMobile) {
const mobileRoute = mobileRoutes.find((r) => r.path === route.path)
if (window.isMobile) { if (mobileRoute) {
const mobileElement = mobileRoutes.find((r) => r.path === route.path) route = mobileRoute
if (mobileElement) {
Element = mobileElement
} }
} }

View File

@ -93,4 +93,23 @@
to { to {
opacity: 0; opacity: 0;
} }
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-5px);
}
60% {
transform: translateY(-3px);
}
} }

View File

@ -10,8 +10,10 @@
.content_wrapper { .content_wrapper {
height: 100%; height: 100%;
width: 100%; width: 100%;
overflow-y: scroll; overflow-y: scroll;
padding-top: 20px;
//padding-top: 20px;
} }
.content_layout { .content_layout {
@ -22,142 +24,139 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 100vw; width: 100%;
padding: 0 10px; padding: 7px;
box-sizing: border-box;
} }
.frameDecorator { .playlist_view {
position: absolute;
left: 0;
z-index: 8000;
width: 100vw;
height: @app_frameDecorator_height;
background-color: rgba(var(--layoutBackgroundColor), 0.8);
filter: blur(4px);
backdrop-filter: blur(10px);
&.top {
top: 0;
transform: translate(0, -6px);
}
&.bottom {
bottom: 0;
transform: translate(0, 6px);
}
}
// FIXMETS FOR MOBILE LAYOUT
.loginPage {
flex-direction: column;
.wallpaper {
width: 100vw;
}
}
.dashboard {
display: flex;
flex-direction: column;
}
.postPage {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 90vh; .play_info_wrapper {
position: relative;
.postCard { .play_info {
&.fullmode { width: 100%;
.wrapper {
height: 76vh;
.post_content { .play_info_cover {
.post_attachments { width: 100%;
height: 60vh; height: 100%;
overflow: hidden; }
}
}
.carousel-root { .list {
.carousel { padding: 30px 10px;
min-height: 200px; }
}
>div { .pagePanels {
display: flex; display: flex;
align-items: center; flex-direction: column;
height: 100%;
} align-items: center;
} justify-content: center;
}
overflow-x: visible;
width: 100%;
height: 100%;
.panel {
width: 100%;
//height: 100%;
&.left {
z-index: 500;
overflow: visible;
overflow-x: visible;
}
&.right {
z-index: 400;
overflow-x: visible;
}
}
.card {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
padding: 5px;
justify-content: space-between;
box-shadow: @card-shadow;
border-radius: 12px;
isolation: unset;
overflow: visible;
.item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 5px 10px;
border-radius: 8px;
.icon {
svg {
margin: 0 !important;
font-size: 1rem;
}
}
.label {
font-size: 0.6rem;
}
&.active {
.icon {
svg {
color: var(--colorPrimary);
}
}
.label {
color: var(--colorPrimary);
}
background-color: var(--background-color-primary);
}
}
}
}
.post-list_wrapper {
.post-list {
padding-top: 10px;
border-radius: 0;
.playlistTimelineEntry {
width: 100%;
.playlistTimelineEntry_content {
.playlistTimelineEntry_thumbnail {
img {
width: 20vw;
height: 20vw;
} }
} }
} }
} }
}
}
.accountProfile { .postCard {
padding: 0;
.contents {
display: flex;
flex-direction: column;
padding: 0;
margin-top: -4.0vh;
padding: 0;
.tabContent {
padding: 0;
padding-top: 26px;
}
.tabMenuWrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
margin: 0;
.ant-menu {
padding: 0;
margin: 0;
}
}
}
}
.liveStream {
flex-direction: column;
.plyr {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 60vh;
border-radius: 6px;
}
.panel {
height: 40vh;
}
}
.postCard {
.post_actionsWrapper {
.actions {
width: 100%; width: 100%;
} }
} }