mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 02:54:15 +00:00
improve mobile mode
This commit is contained in:
parent
163cf09eab
commit
c7a554e455
@ -88,7 +88,7 @@ import { DOMWindow } from "components/RenderWindow"
|
||||
|
||||
import { Icons } from "components/Icons"
|
||||
|
||||
import { ThemeProvider } from "cores/style"
|
||||
import { ThemeProvider } from "cores/style/style.core.jsx"
|
||||
|
||||
import Layout from "./layout"
|
||||
import * as Router from "./router"
|
||||
|
@ -74,7 +74,7 @@ export default class Drawer extends Component {
|
||||
ALLOW_DRAWER_TRANSFORM = true
|
||||
|
||||
componentDidMount() {
|
||||
this.DESKTOP_MODE = !window.isMobile
|
||||
this.DESKTOP_MODE = !app.isMobile
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, nextState) {
|
||||
|
@ -6,31 +6,39 @@ import { Motion, spring } from "react-motion"
|
||||
|
||||
import { Icons, createIconRender } from "components/Icons"
|
||||
|
||||
import { WithPlayerContext, Context } from "contexts/WithPlayerContext"
|
||||
|
||||
import PlayerView from "pages/@mobile-views/player"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
const items = [
|
||||
{
|
||||
id: "creator",
|
||||
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",
|
||||
const PlayerButton = (props) => {
|
||||
const openPlayerView = () => {
|
||||
app.DrawerController.open("player", PlayerView)
|
||||
}
|
||||
]
|
||||
|
||||
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 user = app.userData
|
||||
@ -51,26 +59,10 @@ const AccountButton = (props) => {
|
||||
key: "settings",
|
||||
text: <><Icons.Settings /> <span>Settings</span></>,
|
||||
onClick: () => {
|
||||
app.openSettings()
|
||||
app.navigation.goToSettings()
|
||||
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>
|
||||
}
|
||||
|
||||
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 = {
|
||||
allowed: true,
|
||||
show: true,
|
||||
@ -133,7 +135,7 @@ export default class BottomBar extends React.Component {
|
||||
}
|
||||
|
||||
toggleVisibility = (to) => {
|
||||
if (!window.isMobile) {
|
||||
if (!app.isMobile) {
|
||||
to = false
|
||||
} else {
|
||||
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() {
|
||||
if (this.state.render) {
|
||||
return <div className="bottomBar">
|
||||
@ -195,7 +182,51 @@ export default class BottomBar extends React.Component {
|
||||
}}
|
||||
>
|
||||
<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 />
|
||||
</div>
|
||||
</div>}
|
||||
|
@ -1,4 +1,26 @@
|
||||
@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 {
|
||||
display: flex;
|
||||
@ -24,6 +46,8 @@
|
||||
background-color: var(--background-color-accent);
|
||||
border-radius: 12px 12px 0 0;
|
||||
|
||||
box-shadow: @card-shadow;
|
||||
|
||||
.items {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
@ -227,7 +227,7 @@ export default class Login extends React.Component {
|
||||
>
|
||||
<span><Icons.Lock /> Password</span>
|
||||
<antd.Input.Password
|
||||
placeholder="********"
|
||||
//placeholder="********"
|
||||
onChange={(e) => this.onUpdateInput("password", e.target.value)}
|
||||
onPressEnter={this.nextStep}
|
||||
/>
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@ import * as antd from "antd"
|
||||
|
||||
import { createIconRender } from "components/Icons"
|
||||
|
||||
import NavMenu from "./components/NavMenu"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
export const Panel = (props) => {
|
||||
@ -19,29 +21,6 @@ export const Panel = (props) => {
|
||||
</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 {
|
||||
state = {
|
||||
// if defaultTab is not set, try to get it from query, if not, use the first tab
|
||||
|
@ -1,3 +1,5 @@
|
||||
@import "theme/animations.less";
|
||||
|
||||
.background_media_player {
|
||||
position: relative;
|
||||
|
||||
@ -234,23 +236,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
|
||||
0%,
|
||||
20%,
|
||||
50%,
|
||||
80%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
}
|
@ -79,23 +79,25 @@ export default ({
|
||||
onClick={() => onClickActionsButton("next")}
|
||||
disabled={syncModeLocked}
|
||||
/>
|
||||
<antd.Popover
|
||||
content={React.createElement(
|
||||
AudioVolume,
|
||||
{ onChange: onVolumeUpdate, defaultValue: audioVolume }
|
||||
)}
|
||||
trigger="hover"
|
||||
>
|
||||
<div
|
||||
className="muteButton"
|
||||
onClick={onMuteUpdate}
|
||||
{
|
||||
!app.isMobile && <antd.Popover
|
||||
content={React.createElement(
|
||||
AudioVolume,
|
||||
{ onChange: onVolumeUpdate, defaultValue: audioVolume }
|
||||
)}
|
||||
trigger="hover"
|
||||
>
|
||||
{
|
||||
audioMuted
|
||||
? <Icons.VolumeX />
|
||||
: <Icons.Volume2 />
|
||||
}
|
||||
</div>
|
||||
</antd.Popover>
|
||||
<div
|
||||
className="muteButton"
|
||||
onClick={onMuteUpdate}
|
||||
>
|
||||
{
|
||||
audioMuted
|
||||
? <Icons.VolumeX />
|
||||
: <Icons.Volume2 />
|
||||
}
|
||||
</div>
|
||||
</antd.Popover>
|
||||
}
|
||||
</div>
|
||||
}
|
@ -90,8 +90,9 @@ export class AudioPlayer extends React.Component {
|
||||
className={classnames(
|
||||
"embbededMediaPlayerWrapper",
|
||||
{
|
||||
["hovering"]: this.state.showControls,
|
||||
["hovering"]: this.props.frame !== false && this.state.showControls,
|
||||
["minimized"]: this.context.minimized,
|
||||
["no-frame"]: this.props.frame === false,
|
||||
}
|
||||
)}
|
||||
onMouseEnter={this.onMouse}
|
||||
|
@ -18,6 +18,31 @@
|
||||
|
||||
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 {
|
||||
pointer-events: none;
|
||||
|
||||
|
@ -98,10 +98,14 @@
|
||||
|
||||
font-size: 0.9rem;
|
||||
|
||||
color: var(--text-color);
|
||||
|
||||
.playlistTimelineEntry_statistic {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
color: var(--text-color);
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
width: 35vw;
|
||||
min-width: 300px;
|
||||
max-width: 800px;
|
||||
|
||||
|
||||
//max-width: 600px;
|
||||
//min-height: 165px;
|
||||
//height: 100%;
|
||||
|
@ -368,95 +368,43 @@ export class PostsListsComponent extends React.Component {
|
||||
|
||||
return <div className="post-list_wrapper">
|
||||
<LoadMore
|
||||
ref={this.listRef}
|
||||
className="post-list"
|
||||
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>
|
||||
</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,
|
||||
}
|
||||
})
|
||||
ref={this.listRef}
|
||||
className="post-list"
|
||||
loadingComponent={LoadingComponent}
|
||||
noResultComponent={NoResultComponent}
|
||||
hasMore={this.state.hasMore}
|
||||
fetching={this.state.loading}
|
||||
onBottom={this.onLoadMore}
|
||||
>
|
||||
{
|
||||
!this.state.realtimeUpdates && !app.isMobile && <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>
|
||||
}}
|
||||
</AutoSizer>
|
||||
})
|
||||
}
|
||||
</LoadMore>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,6 @@
|
||||
|
||||
margin: auto;
|
||||
z-index: 150;
|
||||
|
||||
}
|
||||
|
||||
.resume_btn_wrapper {
|
||||
|
@ -51,12 +51,8 @@ export default class Layout extends React.PureComponent {
|
||||
}
|
||||
|
||||
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) {
|
||||
window.isMobile = true
|
||||
|
||||
if (window.app.cores.settings.get("forceMobileMode") || app.isMobile) {
|
||||
app.layout.set("mobile")
|
||||
} else {
|
||||
window.isMobile = false
|
||||
}
|
||||
|
||||
// register events
|
||||
@ -147,7 +143,7 @@ export default class Layout extends React.PureComponent {
|
||||
return JSON.stringify(this.state.renderError)
|
||||
}
|
||||
|
||||
const Layout = Layouts[layoutType]
|
||||
const Layout = Layouts[app.isMobile ? "mobile" : layoutType]
|
||||
|
||||
if (!Layout) {
|
||||
return app.eventBus.emit("runtime.crash", new Error(`Layout type [${layoutType}] not found`))
|
||||
|
@ -9,11 +9,9 @@ export default (props) => {
|
||||
<Modal />
|
||||
|
||||
<antd.Layout.Content className={classnames("content_layout", ...props.layoutPageModesClassnames ?? [])}>
|
||||
<div className={classnames("frameDecorator", "top")} />
|
||||
<div id="transitionLayer" className={classnames("content_wrapper", "fade-transverse-active")}>
|
||||
{React.cloneElement(props.children, props)}
|
||||
</div>
|
||||
<div className={classnames("frameDecorator", "bottom")} />
|
||||
</antd.Layout.Content>
|
||||
|
||||
<BottomBar />
|
||||
|
@ -5,7 +5,7 @@ import classnames from "classnames"
|
||||
import { Drawer, Sidedrawer } from "components/Layout"
|
||||
|
||||
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 />
|
||||
<Sidedrawer />
|
||||
<div id="transitionLayer" className="fade-transverse-active">
|
||||
|
12
packages/app/src/pages/@mobile-views/player/index.jsx
Normal file
12
packages/app/src/pages/@mobile-views/player/index.jsx
Normal 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>
|
||||
}
|
8
packages/app/src/pages/@mobile-views/player/index.less
Normal file
8
packages/app/src/pages/@mobile-views/player/index.less
Normal file
@ -0,0 +1,8 @@
|
||||
.__mobile-player-view {
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
@ -258,7 +258,7 @@ export default class Account extends React.Component {
|
||||
<div className="tabMenuWrapper">
|
||||
<antd.Menu
|
||||
className="tabMenu"
|
||||
mode={window.isMobile ? "horizontal" : "vertical"}
|
||||
mode={app.isMobile ? "horizontal" : "vertical"}
|
||||
selectedKeys={[this.state.tabActiveKey]}
|
||||
onClick={(e) => this.handlePageTransition(e.key)}
|
||||
>
|
||||
|
35
packages/app/src/pages/index.mobile.jsx
Normal file
35
packages/app/src/pages/index.mobile.jsx
Normal 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
|
||||
/>
|
||||
}
|
||||
}
|
@ -75,7 +75,7 @@ export default (props) => {
|
||||
|
||||
<div className="content">
|
||||
<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>
|
||||
|
||||
{
|
||||
|
@ -1,12 +1,15 @@
|
||||
import React from "react"
|
||||
|
||||
import "./index.less"
|
||||
import "./index.mobile.less"
|
||||
|
||||
export default (props) => {
|
||||
const [wallpaperData, setWallpaperData] = React.useState(null)
|
||||
|
||||
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)
|
||||
return []
|
||||
})
|
||||
@ -19,12 +22,12 @@ export default (props) => {
|
||||
|
||||
React.useEffect(() => {
|
||||
if (app.userData) {
|
||||
return app.goMain()
|
||||
return app.navigation.goMain()
|
||||
}
|
||||
|
||||
setRandomWallpaper()
|
||||
|
||||
app.eventBus.emit("app.createLogin", {
|
||||
app.controls.openLoginForm({
|
||||
defaultLocked: true,
|
||||
})
|
||||
}, [])
|
||||
@ -36,9 +39,9 @@ export default (props) => {
|
||||
}}
|
||||
className="wallpaper"
|
||||
>
|
||||
<p>
|
||||
{/* <p>
|
||||
{wallpaperData?.author ? wallpaperData.author : null}
|
||||
</p>
|
||||
</p> */}
|
||||
</div>
|
||||
</div>
|
||||
}
|
22
packages/app/src/pages/login/index.mobile.less
Normal file
22
packages/app/src/pages/login/index.mobile.less
Normal 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;
|
||||
}
|
||||
}
|
@ -601,10 +601,16 @@ export default class SyncLyrics extends React.Component {
|
||||
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.applyVariant("dark")
|
||||
app.layout.floatingStack.toogleGlobalVisibility(false)
|
||||
|
||||
// request full screen to browser
|
||||
if (document.fullscreenEnabled) {
|
||||
@ -640,10 +646,16 @@ export default class SyncLyrics extends React.Component {
|
||||
|
||||
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.applyInitialVariant()
|
||||
app.layout.floatingStack.toogleGlobalVisibility(true)
|
||||
|
||||
// exit full screen
|
||||
if (document.fullscreenEnabled) {
|
||||
|
@ -279,7 +279,9 @@ export default class PlaylistCreatorSteps extends React.Component {
|
||||
okType: "danger",
|
||||
cancelText: "Cancel",
|
||||
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) {
|
||||
app.message.success("Playlist deleted")
|
||||
|
@ -105,7 +105,7 @@ export default (props) => {
|
||||
|
||||
return <div
|
||||
className={
|
||||
classnames("play", playlist.type)
|
||||
classnames("playlist_view", playlist.type)
|
||||
}
|
||||
>
|
||||
<div className="play_info_wrapper">
|
||||
|
@ -1,4 +1,4 @@
|
||||
.play {
|
||||
.playlist_view {
|
||||
display: grid;
|
||||
|
||||
grid-template-columns: 30vw 1fr;
|
||||
@ -54,15 +54,12 @@
|
||||
|
||||
background-color: black;
|
||||
border-radius: 12px;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
border-radius: 12px;
|
||||
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
@ -591,7 +591,7 @@ export default () => {
|
||||
className={classnames(
|
||||
"settings_wrapper",
|
||||
{
|
||||
["mobile"]: window.isMobile,
|
||||
["mobile"]: app.isMobile,
|
||||
}
|
||||
)}
|
||||
>
|
||||
|
@ -46,7 +46,7 @@ const mobileRoutes = Object.keys(pathsMobile).map((route) => {
|
||||
|
||||
return {
|
||||
path,
|
||||
element: pathsMobile[path]
|
||||
element: pathsMobile[route]
|
||||
}
|
||||
})
|
||||
|
||||
@ -192,13 +192,11 @@ export const PageRender = React.memo((props) => {
|
||||
return <Routes>
|
||||
{
|
||||
routes.map((route, index) => {
|
||||
let Element = route.element
|
||||
if (app.isMobile) {
|
||||
const mobileRoute = mobileRoutes.find((r) => r.path === route.path)
|
||||
|
||||
if (window.isMobile) {
|
||||
const mobileElement = mobileRoutes.find((r) => r.path === route.path)
|
||||
|
||||
if (mobileElement) {
|
||||
Element = mobileElement
|
||||
if (mobileRoute) {
|
||||
route = mobileRoute
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,4 +93,23 @@
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
|
||||
0%,
|
||||
20%,
|
||||
50%,
|
||||
80%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
}
|
@ -10,8 +10,10 @@
|
||||
.content_wrapper {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
overflow-y: scroll;
|
||||
padding-top: 20px;
|
||||
|
||||
//padding-top: 20px;
|
||||
}
|
||||
|
||||
.content_layout {
|
||||
@ -22,142 +24,139 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100vw;
|
||||
padding: 0 10px;
|
||||
width: 100%;
|
||||
padding: 7px;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.frameDecorator {
|
||||
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 {
|
||||
.playlist_view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
height: 90vh;
|
||||
.play_info_wrapper {
|
||||
position: relative;
|
||||
|
||||
.postCard {
|
||||
&.fullmode {
|
||||
.wrapper {
|
||||
height: 76vh;
|
||||
.play_info {
|
||||
width: 100%;
|
||||
|
||||
.post_content {
|
||||
.post_attachments {
|
||||
height: 60vh;
|
||||
overflow: hidden;
|
||||
.play_info_cover {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-root {
|
||||
.carousel {
|
||||
min-height: 200px;
|
||||
.list {
|
||||
padding: 30px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
>div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.pagePanels {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
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 {
|
||||
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 {
|
||||
.postCard {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user