Merge branch 'csstheming' into 'master'
Csstheming See merge request lukas/openmediacenter!8
This commit is contained in:
commit
13336cbf1c
@ -22,13 +22,15 @@ class Settings extends RequestBase {
|
|||||||
$videopath = $_POST['videopath'];
|
$videopath = $_POST['videopath'];
|
||||||
$tvshowpath = $_POST['tvshowpath'];
|
$tvshowpath = $_POST['tvshowpath'];
|
||||||
$tmdbsupport = $_POST['tmdbsupport'];
|
$tmdbsupport = $_POST['tmdbsupport'];
|
||||||
|
$darkmodeenabled = $_POST['darkmodeenabled'];
|
||||||
|
|
||||||
$query = "UPDATE settings SET
|
$query = "UPDATE settings SET
|
||||||
video_path='$videopath',
|
video_path='$videopath',
|
||||||
episode_path='$tvshowpath',
|
episode_path='$tvshowpath',
|
||||||
password='$password',
|
password='$password',
|
||||||
mediacenter_name='$mediacentername',
|
mediacenter_name='$mediacentername',
|
||||||
TMDB_grabbing=$tmdbsupport
|
TMDB_grabbing=$tmdbsupport,
|
||||||
|
DarkMode=$darkmodeenabled
|
||||||
WHERE 1";
|
WHERE 1";
|
||||||
|
|
||||||
if ($this->conn->query($query) === true) {
|
if ($this->conn->query($query) === true) {
|
||||||
@ -44,12 +46,10 @@ class Settings extends RequestBase {
|
|||||||
$result = $this->conn->query($query);
|
$result = $this->conn->query($query);
|
||||||
|
|
||||||
$r = mysqli_fetch_assoc($result);
|
$r = mysqli_fetch_assoc($result);
|
||||||
if ($r['password'] != "-1") {
|
|
||||||
$r['passwordEnabled'] = true;
|
$r['passwordEnabled'] = $r['password'] != "-1";
|
||||||
} else {
|
|
||||||
$r['passwordEnabled'] = false;
|
|
||||||
}
|
|
||||||
unset($r['password']);
|
unset($r['password']);
|
||||||
|
$r['DarkMode'] = (bool)($r['DarkMode'] != '0');
|
||||||
echo json_encode($r);
|
echo json_encode($r);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,8 @@ create table settings
|
|||||||
episode_path varchar(255) null,
|
episode_path varchar(255) null,
|
||||||
password varchar(32) default '-1' null,
|
password varchar(32) default '-1' null,
|
||||||
mediacenter_name varchar(32) default 'OpenMediaCenter' null,
|
mediacenter_name varchar(32) default 'OpenMediaCenter' null,
|
||||||
|
TMDB_grabbing tinyint null,
|
||||||
|
DarkMode tinyint default 0 null
|
||||||
PRIMARY KEY (id)
|
PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
12
src/App.css
12
src/App.css
@ -1,12 +0,0 @@
|
|||||||
.nav-item {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-link {
|
|
||||||
color: rgba(255, 255, 255, .5);
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-link:hover {
|
|
||||||
color: rgba(255, 255, 255, 1);
|
|
||||||
}
|
|
55
src/App.js
55
src/App.js
@ -1,10 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import "./App.css"
|
|
||||||
import HomePage from "./pages/HomePage/HomePage";
|
import HomePage from "./pages/HomePage/HomePage";
|
||||||
import RandomPage from "./pages/RandomPage/RandomPage";
|
import RandomPage from "./pages/RandomPage/RandomPage";
|
||||||
|
import GlobalInfos from "./GlobalInfos";
|
||||||
|
|
||||||
// include bootstraps css
|
// include bootstraps css
|
||||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||||
|
import style from './App.module.css'
|
||||||
|
|
||||||
import SettingsPage from "./pages/SettingsPage/SettingsPage";
|
import SettingsPage from "./pages/SettingsPage/SettingsPage";
|
||||||
import CategoryPage from "./pages/CategoryPage/CategoryPage";
|
import CategoryPage from "./pages/CategoryPage/CategoryPage";
|
||||||
|
|
||||||
@ -32,7 +34,9 @@ class App extends React.Component {
|
|||||||
fetch('/api/Settings.php', {method: 'POST', body: updateRequest})
|
fetch('/api/Settings.php', {method: 'POST', body: updateRequest})
|
||||||
.then((response) => response.json()
|
.then((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
console.log(result);
|
// set theme
|
||||||
|
GlobalInfos.enableDarkTheme(result.DarkMode);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
generalSettingsLoaded: true,
|
generalSettingsLoaded: true,
|
||||||
passwordsupport: result.passwordEnabled,
|
passwordsupport: result.passwordEnabled,
|
||||||
@ -79,38 +83,27 @@ class App extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
|
// add the main theme to the page body
|
||||||
|
document.body.className = themeStyle.backgroundcolor;
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<nav className="navbar navbar-expand-sm bg-primary navbar-dark">
|
<div className={[style.navcontainer, themeStyle.backgroundcolor, themeStyle.textcolor, themeStyle.hrcolor].join(' ')}>
|
||||||
<div className="navbar-brand">{this.state.mediacentername}</div>
|
<div className={style.navbrand}>{this.state.mediacentername}</div>
|
||||||
|
|
||||||
<ul className="navbar-nav">
|
<div className={[style.navitem, themeStyle.navitem, this.state.page === "default" ? style.navitemselected : {}].join(' ')}
|
||||||
<li className="nav-item">
|
onClick={() => this.setState({page: "default"})}>Home
|
||||||
<div className="nav-link"
|
</div>
|
||||||
style={this.state.page === "default" ? {color: "rgba(255,255,255,.75"} : {}}
|
<div className={[style.navitem, themeStyle.navitem, this.state.page === "random" ? style.navitemselected : {}].join(' ')}
|
||||||
onClick={() => this.setState({page: "default"})}>Home
|
onClick={() => this.setState({page: "random"})}>Random Video
|
||||||
</div>
|
</div>
|
||||||
</li>
|
<div className={[style.navitem, themeStyle.navitem, this.state.page === "categories" ? style.navitemselected : {}].join(' ')}
|
||||||
<li className="nav-item">
|
onClick={() => this.setState({page: "categories"})}>Categories
|
||||||
<div className="nav-link"
|
</div>
|
||||||
style={this.state.page === "random" ? {color: "rgba(255,255,255,.75"} : {}}
|
<div className={[style.navitem, themeStyle.navitem, this.state.page === "settings" ? style.navitemselected : {}].join(' ')}
|
||||||
onClick={() => this.setState({page: "random"})}>Random Video
|
onClick={() => this.setState({page: "settings"})}>Settings
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
<li className="nav-item">
|
|
||||||
<div className="nav-link"
|
|
||||||
style={this.state.page === "categories" ? {color: "rgba(255,255,255,.75"} : {}}
|
|
||||||
onClick={() => this.setState({page: "categories"})}>Categories
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li className="nav-item">
|
|
||||||
<div className="nav-link"
|
|
||||||
style={this.state.page === "settings" ? {color: "rgba(255,255,255,.75"} : {}}
|
|
||||||
onClick={() => this.setState({page: "settings"})}>Settings
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
{this.state.generalSettingsLoaded ? this.MainBody() : "loading"}
|
{this.state.generalSettingsLoaded ? this.MainBody() : "loading"}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
54
src/App.module.css
Normal file
54
src/App.module.css
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
.navitem {
|
||||||
|
float: left;
|
||||||
|
margin-left: 20px;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.6;
|
||||||
|
|
||||||
|
font-size: large;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navitem:hover {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity .5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navitem::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 0;
|
||||||
|
height: 2px;
|
||||||
|
transition: width .3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navitem:hover::after {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.navitemselected {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcontainer {
|
||||||
|
padding-top: 20px;
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
|
||||||
|
border-width: 0;
|
||||||
|
border-style: dotted;
|
||||||
|
border-bottom-width: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbrand {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
font-size: large;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: capitalize;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -10,19 +10,19 @@ describe('<App/>', function () {
|
|||||||
|
|
||||||
it('renders title', () => {
|
it('renders title', () => {
|
||||||
const wrapper = shallow(<App/>);
|
const wrapper = shallow(<App/>);
|
||||||
expect(wrapper.find('.navbar-brand').text()).toBe('OpenMediaCenter');
|
expect(wrapper.find('.navbrand').text()).toBe('OpenMediaCenter');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('are navlinks correct', function () {
|
it('are navlinks correct', function () {
|
||||||
const wrapper = shallow(<App/>);
|
const wrapper = shallow(<App/>);
|
||||||
expect(wrapper.find('nav').find('li')).toHaveLength(4);
|
expect(wrapper.find('.navitem')).toHaveLength(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('simulate video view change ', function () {
|
it('simulate video view change ', function () {
|
||||||
const wrapper = shallow(<App/>);
|
const wrapper = shallow(<App/>);
|
||||||
wrapper.setState({generalSettingsLoaded: true}); // simulate fetch to have already finisheed
|
wrapper.setState({generalSettingsLoaded: true}); // simulate fetch to have already finisheed
|
||||||
|
|
||||||
wrapper.instance().changeRootElement(<div id='testit'></div>);
|
wrapper.instance().changeRootElement(<div id='testit'/>);
|
||||||
|
|
||||||
expect(wrapper.find("#testit")).toHaveLength(1);
|
expect(wrapper.find("#testit")).toHaveLength(1);
|
||||||
});
|
});
|
||||||
@ -31,7 +31,7 @@ describe('<App/>', function () {
|
|||||||
const wrapper = shallow(<App/>);
|
const wrapper = shallow(<App/>);
|
||||||
wrapper.setState({generalSettingsLoaded: true}); // simulate fetch to have already finisheed
|
wrapper.setState({generalSettingsLoaded: true}); // simulate fetch to have already finisheed
|
||||||
|
|
||||||
wrapper.instance().changeRootElement(<div id='testit'></div>);
|
wrapper.instance().changeRootElement(<div id='testit'/>);
|
||||||
|
|
||||||
expect(wrapper.find("#testit")).toHaveLength(1);
|
expect(wrapper.find("#testit")).toHaveLength(1);
|
||||||
|
|
||||||
@ -44,9 +44,9 @@ describe('<App/>', function () {
|
|||||||
const wrapper = shallow(<App/>);
|
const wrapper = shallow(<App/>);
|
||||||
wrapper.setState({generalSettingsLoaded: true}); // simulate fetch to have already finisheed
|
wrapper.setState({generalSettingsLoaded: true}); // simulate fetch to have already finisheed
|
||||||
|
|
||||||
wrapper.find(".nav-link").findWhere(t => t.text() === "Random Video" && t.type() === "div").simulate("click");
|
wrapper.find(".navitem").findWhere(t => t.text() === "Random Video" && t.type() === "div").simulate("click");
|
||||||
|
|
||||||
wrapper.instance().changeRootElement(<div id='testit'></div>);
|
wrapper.instance().changeRootElement(<div id='testit'/>);
|
||||||
|
|
||||||
expect(wrapper.find("#testit")).toHaveLength(1);
|
expect(wrapper.find("#testit")).toHaveLength(1);
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ describe('<App/>', function () {
|
|||||||
|
|
||||||
wrapper.setState({page: "wrongvalue"});
|
wrapper.setState({page: "wrongvalue"});
|
||||||
expect(wrapper.find("HomePage")).toHaveLength(0);
|
expect(wrapper.find("HomePage")).toHaveLength(0);
|
||||||
wrapper.find(".nav-link").findWhere(t => t.text() === "Home" && t.type() === "div").simulate("click");
|
wrapper.find(".navitem").findWhere(t => t.text() === "Home" && t.type() === "div").simulate("click");
|
||||||
expect(wrapper.find("HomePage")).toHaveLength(1);
|
expect(wrapper.find("HomePage")).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ describe('<App/>', function () {
|
|||||||
wrapper.setState({generalSettingsLoaded: true}); // simulate fetch to have already finisheed
|
wrapper.setState({generalSettingsLoaded: true}); // simulate fetch to have already finisheed
|
||||||
|
|
||||||
expect(wrapper.find("CategoryPage")).toHaveLength(0);
|
expect(wrapper.find("CategoryPage")).toHaveLength(0);
|
||||||
wrapper.find(".nav-link").findWhere(t => t.text() === "Categories" && t.type() === "div").simulate("click");
|
wrapper.find(".navitem").findWhere(t => t.text() === "Categories" && t.type() === "div").simulate("click");
|
||||||
expect(wrapper.find("CategoryPage")).toHaveLength(1);
|
expect(wrapper.find("CategoryPage")).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ describe('<App/>', function () {
|
|||||||
wrapper.setState({generalSettingsLoaded: true}); // simulate fetch to have already finisheed
|
wrapper.setState({generalSettingsLoaded: true}); // simulate fetch to have already finisheed
|
||||||
|
|
||||||
expect(wrapper.find("SettingsPage")).toHaveLength(0);
|
expect(wrapper.find("SettingsPage")).toHaveLength(0);
|
||||||
wrapper.find(".nav-link").findWhere(t => t.text() === "Settings" && t.type() === "div").simulate("click");
|
wrapper.find(".navitem").findWhere(t => t.text() === "Settings" && t.type() === "div").simulate("click");
|
||||||
expect(wrapper.find("SettingsPage")).toHaveLength(1);
|
expect(wrapper.find("SettingsPage")).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
40
src/AppDarkTheme.module.css
Normal file
40
src/AppDarkTheme.module.css
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* The coloring elements for dark theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
.backgroundcolor {
|
||||||
|
background-color: #141520;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textcolor {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtextcolor {
|
||||||
|
color: #dedad6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lighttextcolor {
|
||||||
|
color: #d5d5d5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navitem::after {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hrcolor {
|
||||||
|
border-color: rgba(255, 255, 255, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.secbackground {
|
||||||
|
background-color: #3c3d48;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thirdbackground {
|
||||||
|
background-color: #141520;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview:hover {
|
||||||
|
box-shadow: rgba(255, 255, 255, 0.7) 0 0 0 5px;
|
||||||
|
}
|
||||||
|
|
39
src/AppLightTheme.module.css
Normal file
39
src/AppLightTheme.module.css
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* The coloring elements for light theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
.navitem::after {
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.backgroundcolor {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textcolor {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtextcolor {
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lighttextcolor {
|
||||||
|
color: #3d3d3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hrcolor {
|
||||||
|
border-color: rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.secbackground {
|
||||||
|
background-color: #a8c3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thirdbackground {
|
||||||
|
background-color: #8ca3fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview:hover {
|
||||||
|
box-shadow: rgba(2, 12, 27, 0.7) 0 0 0 5px;
|
||||||
|
}
|
23
src/GlobalInfos.js
Normal file
23
src/GlobalInfos.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import darktheme from "./AppDarkTheme.module.css";
|
||||||
|
import lighttheme from "./AppLightTheme.module.css";
|
||||||
|
|
||||||
|
class StaticInfos {
|
||||||
|
#darktheme = true;
|
||||||
|
|
||||||
|
isDarkTheme() {
|
||||||
|
return this.#darktheme;
|
||||||
|
};
|
||||||
|
|
||||||
|
enableDarkTheme(enable = true){
|
||||||
|
this.#darktheme = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
getThemeStyle(){
|
||||||
|
return this.isDarkTheme() ? darktheme : lighttheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const GlobalInfos = new StaticInfos();
|
||||||
|
//Object.freeze(StaticInfos);
|
||||||
|
|
||||||
|
export default GlobalInfos;
|
24
src/GlobalInfos.test.js
Normal file
24
src/GlobalInfos.test.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React from "react";
|
||||||
|
import GlobalInfos from "./GlobalInfos";
|
||||||
|
|
||||||
|
describe('<GlobalInfos/>', function () {
|
||||||
|
it('always same instance ', function () {
|
||||||
|
GlobalInfos.enableDarkTheme(true);
|
||||||
|
|
||||||
|
expect(GlobalInfos.isDarkTheme()).toBe(true);
|
||||||
|
|
||||||
|
GlobalInfos.enableDarkTheme(false);
|
||||||
|
|
||||||
|
expect(GlobalInfos.isDarkTheme()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('test default theme', function () {
|
||||||
|
expect(GlobalInfos.isDarkTheme()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('test receive of stylesheet', function () {
|
||||||
|
const style = GlobalInfos.getThemeStyle();
|
||||||
|
|
||||||
|
expect(style.navitem).not.toBeNull();
|
||||||
|
});
|
||||||
|
});
|
@ -1,5 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import style from "./PageTitle.module.css"
|
import style from "./PageTitle.module.css"
|
||||||
|
import GlobalInfos from "../../GlobalInfos";
|
||||||
|
|
||||||
class PageTitle extends React.Component {
|
class PageTitle extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -10,17 +11,33 @@ class PageTitle extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
return (
|
||||||
<div className={style.pageheader}>
|
<div className={style.pageheader + ' ' + themeStyle.backgroundcolor}>
|
||||||
<span className={style.pageheadertitle}>{this.props.title}</span>
|
<span className={style.pageheadertitle + ' ' + themeStyle.textcolor}>{this.props.title}</span>
|
||||||
<span className={style.pageheadersubtitle}>{this.props.subtitle}</span>
|
<span className={style.pageheadersubtitle + ' ' + themeStyle.textcolor}>{this.props.subtitle}</span>
|
||||||
<>
|
<>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</>
|
</>
|
||||||
<hr/>
|
<Line/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PageTitle;
|
/**
|
||||||
|
* class to override default <hr> color and styling
|
||||||
|
* use this for horizontal lines to use the current active theming
|
||||||
|
*/
|
||||||
|
export class Line extends React.Component {
|
||||||
|
render() {
|
||||||
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<hr className={themeStyle.hrcolor}/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PageTitle;
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
.pageheader {
|
.pageheader {
|
||||||
margin-bottom: 20px;
|
padding: 20px 12% 20px 22%;
|
||||||
margin-top: 20px;
|
|
||||||
padding-left: 22%;
|
|
||||||
padding-right: 12%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.pageheadertitle {
|
.pageheadertitle {
|
||||||
@ -11,7 +8,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pageheadersubtitle {
|
.pageheadersubtitle {
|
||||||
font-size: 23pt;
|
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
|
font-size: 23pt;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ describe('<Preview/>', function () {
|
|||||||
it('renders pagetitle prop', function () {
|
it('renders pagetitle prop', function () {
|
||||||
const wrapper = shallow(<PageTitle title='testtitle'/>);
|
const wrapper = shallow(<PageTitle title='testtitle'/>);
|
||||||
|
|
||||||
expect(wrapper.find(".pageheader").text()).toBe("testtitle");
|
expect(wrapper.find(".pageheader").text()).toBe("testtitle<Line />");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders subtitle prop', function () {
|
it('renders subtitle prop', function () {
|
||||||
|
@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import style from "./Preview.module.css";
|
import style from "./Preview.module.css";
|
||||||
import Player from "../../pages/Player/Player";
|
import Player from "../../pages/Player/Player";
|
||||||
import {Spinner} from "react-bootstrap";
|
import {Spinner} from "react-bootstrap";
|
||||||
|
import GlobalInfos from "../../GlobalInfos";
|
||||||
|
|
||||||
class Preview extends React.Component {
|
class Preview extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
@ -33,9 +34,10 @@ class Preview extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
return (
|
||||||
<div className={style.videopreview} onClick={() => this.itemClick()}>
|
<div className={style.videopreview + ' ' + themeStyle.secbackground + ' '+ themeStyle.preview} onClick={() => this.itemClick()}>
|
||||||
<div className={style.previewtitle}>{this.state.name}</div>
|
<div className={style.previewtitle + ' '+ themeStyle.lighttextcolor}>{this.state.name}</div>
|
||||||
<div className={style.previewpic}>
|
<div className={style.previewpic}>
|
||||||
{this.state.previewpicture !== null ?
|
{this.state.previewpicture !== null ?
|
||||||
<img className={style.previewimage}
|
<img className={style.previewimage}
|
||||||
@ -63,9 +65,10 @@ class Preview extends React.Component {
|
|||||||
|
|
||||||
export class TagPreview extends React.Component {
|
export class TagPreview extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
return (
|
||||||
<div className={style.videopreview + ' ' + style.tagpreview} onClick={() => this.itemClick()}>
|
<div className={style.videopreview + ' ' + style.tagpreview + ' ' + themeStyle.secbackground + ' '+ themeStyle.preview} onClick={() => this.itemClick()}>
|
||||||
<div className={style.tagpreviewtitle}>
|
<div className={style.tagpreviewtitle + ' ' + themeStyle.lighttextcolor}>
|
||||||
{this.props.name}
|
{this.props.name}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
.previewtitle {
|
.previewtitle {
|
||||||
color: #3d3d3d;
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
font-size: smaller;
|
font-size: smaller;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
@ -33,10 +34,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.videopreview {
|
.videopreview {
|
||||||
background-color: #a8c3ff;
|
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
/*background-color: #7F7F7F;*/
|
|
||||||
float: left;
|
float: left;
|
||||||
margin-left: 25px;
|
margin-left: 25px;
|
||||||
margin-top: 25px;
|
margin-top: 25px;
|
||||||
@ -44,7 +43,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.videopreview:hover {
|
.videopreview:hover {
|
||||||
box-shadow: rgba(2, 12, 27, 0.7) 0 0 0 5px;
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: all 300ms;
|
transition: all 300ms;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import style from "./SideBar.module.css"
|
import style from "./SideBar.module.css"
|
||||||
|
import GlobalInfos from "../../GlobalInfos";
|
||||||
|
|
||||||
class SideBar extends React.Component {
|
class SideBar extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (<div className={style.sideinfo}>
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
|
return (<div className={style.sideinfo + ' '+ themeStyle.secbackground}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
@ -11,16 +13,18 @@ class SideBar extends React.Component {
|
|||||||
|
|
||||||
export class SideBarTitle extends React.Component {
|
export class SideBarTitle extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
return (
|
||||||
<div className={style.sidebartitle}>{this.props.children}</div>
|
<div className={style.sidebartitle + ' '+ themeStyle.subtextcolor}>{this.props.children}</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SideBarItem extends React.Component {
|
export class SideBarItem extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
return (
|
||||||
<div className={style.sidebarinfo}>{this.props.children}</div>
|
<div className={style.sidebarinfo + ' ' + themeStyle.thirdbackground + ' ' + themeStyle.lighttextcolor}>{this.props.children}</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
.sideinfo {
|
.sideinfo {
|
||||||
background-color: #b4c7fe;
|
|
||||||
border: 2px #3574fe solid;
|
border: 2px #3574fe solid;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
float: left;
|
float: left;
|
||||||
@ -16,7 +15,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sidebarinfo {
|
.sidebarinfo {
|
||||||
background-color: #8ca3fc;
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
padding: 2px 10px 2px 15px;
|
padding: 2px 10px 2px 15px;
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
body {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
||||||
sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
margin: 0;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import './index.css';
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
|
@ -5,7 +5,7 @@ import videocontainerstyle from "../../elements/VideoContainer/VideoContainer.mo
|
|||||||
|
|
||||||
import {TagPreview} from "../../elements/Preview/Preview";
|
import {TagPreview} from "../../elements/Preview/Preview";
|
||||||
import NewTagPopup from "../../elements/NewTagPopup/NewTagPopup";
|
import NewTagPopup from "../../elements/NewTagPopup/NewTagPopup";
|
||||||
import PageTitle from "../../elements/PageTitle/PageTitle";
|
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
|
||||||
import VideoContainer from "../../elements/VideoContainer/VideoContainer";
|
import VideoContainer from "../../elements/VideoContainer/VideoContainer";
|
||||||
|
|
||||||
class CategoryPage extends React.Component {
|
class CategoryPage extends React.Component {
|
||||||
@ -56,7 +56,7 @@ class CategoryPage extends React.Component {
|
|||||||
this.loadTag(e.props.category)
|
this.loadTag(e.props.category)
|
||||||
}
|
}
|
||||||
}}>HD</Tag>
|
}}>HD</Tag>
|
||||||
<hr/>
|
<Line/>
|
||||||
<button data-testid='btnaddtag' className='btn btn-success' onClick={() => {
|
<button data-testid='btnaddtag' className='btn btn-success' onClick={() => {
|
||||||
this.setState({popupvisible: true})
|
this.setState({popupvisible: true})
|
||||||
}}>Add a new Tag!
|
}}>Add a new Tag!
|
||||||
|
@ -4,7 +4,7 @@ import Tag from "../../elements/Tag/Tag";
|
|||||||
import VideoContainer from "../../elements/VideoContainer/VideoContainer";
|
import VideoContainer from "../../elements/VideoContainer/VideoContainer";
|
||||||
|
|
||||||
import style from "./HomePage.module.css"
|
import style from "./HomePage.module.css"
|
||||||
import PageTitle from "../../elements/PageTitle/PageTitle";
|
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
|
||||||
|
|
||||||
class HomePage extends React.Component {
|
class HomePage extends React.Component {
|
||||||
/** keyword variable needed temporary store search keyword */
|
/** keyword variable needed temporary store search keyword */
|
||||||
@ -138,13 +138,13 @@ class HomePage extends React.Component {
|
|||||||
</PageTitle>
|
</PageTitle>
|
||||||
<SideBar>
|
<SideBar>
|
||||||
<SideBarTitle>Infos:</SideBarTitle>
|
<SideBarTitle>Infos:</SideBarTitle>
|
||||||
<hr/>
|
<Line/>
|
||||||
<SideBarItem><b>{this.state.sideinfo.videonr}</b> Videos Total!</SideBarItem>
|
<SideBarItem><b>{this.state.sideinfo.videonr}</b> Videos Total!</SideBarItem>
|
||||||
<SideBarItem><b>{this.state.sideinfo.fullhdvideonr}</b> FULL-HD Videos!</SideBarItem>
|
<SideBarItem><b>{this.state.sideinfo.fullhdvideonr}</b> FULL-HD Videos!</SideBarItem>
|
||||||
<SideBarItem><b>{this.state.sideinfo.hdvideonr}</b> HD Videos!</SideBarItem>
|
<SideBarItem><b>{this.state.sideinfo.hdvideonr}</b> HD Videos!</SideBarItem>
|
||||||
<SideBarItem><b>{this.state.sideinfo.sdvideonr}</b> SD Videos!</SideBarItem>
|
<SideBarItem><b>{this.state.sideinfo.sdvideonr}</b> SD Videos!</SideBarItem>
|
||||||
<SideBarItem><b>{this.state.sideinfo.tagnr}</b> different Tags!</SideBarItem>
|
<SideBarItem><b>{this.state.sideinfo.tagnr}</b> different Tags!</SideBarItem>
|
||||||
<hr/>
|
<Line/>
|
||||||
<SideBarTitle>Default Tags:</SideBarTitle>
|
<SideBarTitle>Default Tags:</SideBarTitle>
|
||||||
<Tag viewbinding={this.props.viewbinding}>All</Tag>
|
<Tag viewbinding={this.props.viewbinding}>All</Tag>
|
||||||
<Tag viewbinding={this.props.viewbinding}>FullHd</Tag>
|
<Tag viewbinding={this.props.viewbinding}>FullHd</Tag>
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import style from "./Player.module.css"
|
import style from "./Player.module.css"
|
||||||
|
|
||||||
import {PlyrComponent} from 'plyr-react';
|
import {PlyrComponent} from 'plyr-react';
|
||||||
import SideBar, {SideBarItem, SideBarTitle} from "../../elements/SideBar/SideBar";
|
import SideBar, {SideBarItem, SideBarTitle} from "../../elements/SideBar/SideBar";
|
||||||
import Tag from "../../elements/Tag/Tag";
|
import Tag from "../../elements/Tag/Tag";
|
||||||
import AddTagPopup from "../../elements/AddTagPopup/AddTagPopup";
|
import AddTagPopup from "../../elements/AddTagPopup/AddTagPopup";
|
||||||
import PageTitle from "../../elements/PageTitle/PageTitle";
|
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
|
||||||
|
|
||||||
|
|
||||||
class Player extends React.Component {
|
class Player extends React.Component {
|
||||||
@ -53,14 +54,13 @@ class Player extends React.Component {
|
|||||||
|
|
||||||
<SideBar>
|
<SideBar>
|
||||||
<SideBarTitle>Infos:</SideBarTitle>
|
<SideBarTitle>Infos:</SideBarTitle>
|
||||||
<hr/>
|
<Line/>
|
||||||
<SideBarItem><b>{this.state.likes}</b> Likes!</SideBarItem>
|
<SideBarItem><b>{this.state.likes}</b> Likes!</SideBarItem>
|
||||||
{this.state.quality !== 0 ?
|
{this.state.quality !== 0 ?
|
||||||
<SideBarItem><b>{this.state.quality}p</b> Quality!</SideBarItem> : null}
|
<SideBarItem><b>{this.state.quality}p</b> Quality!</SideBarItem> : null}
|
||||||
{this.state.length !== 0 ?
|
{this.state.length !== 0 ?
|
||||||
<SideBarItem><b>{Math.round(this.state.length / 60)}</b> Minutes of
|
<SideBarItem><b>{Math.round(this.state.length / 60)}</b> Minutes of length!</SideBarItem>: null}
|
||||||
length!</SideBarItem> : null}
|
<Line/>
|
||||||
<hr/>
|
|
||||||
<SideBarTitle>Tags:</SideBarTitle>
|
<SideBarTitle>Tags:</SideBarTitle>
|
||||||
{this.state.tags.map((m) => (
|
{this.state.tags.map((m) => (
|
||||||
<Tag
|
<Tag
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
margin-top: 25px;
|
margin-top: 25px;
|
||||||
width: 60%;
|
width: 60%;
|
||||||
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.videoactions {
|
.videoactions {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {Button, Col, Form} from "react-bootstrap";
|
import {Button, Col, Form} from "react-bootstrap";
|
||||||
import style from "./GeneralSettings.module.css"
|
import style from "./GeneralSettings.module.css"
|
||||||
|
import GlobalInfos from "../../GlobalInfos";
|
||||||
|
|
||||||
class GeneralSettings extends React.Component {
|
class GeneralSettings extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -37,9 +38,10 @@ class GeneralSettings extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={style.GeneralForm}>
|
<div className={style.GeneralForm + ' ' + themeStyle.subtextcolor}>
|
||||||
<Form data-testid='mainformsettings' onSubmit={(e) => {
|
<Form data-testid='mainformsettings' onSubmit={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.saveSettings();
|
this.saveSettings();
|
||||||
@ -70,6 +72,14 @@ class GeneralSettings extends React.Component {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{this.state.passwordsupport ?
|
||||||
|
<Form.Group data-testid="passwordfield">
|
||||||
|
<Form.Label>Password</Form.Label>
|
||||||
|
<Form.Control type="password" placeholder="**********" value={this.state.password}
|
||||||
|
onChange={(e) => this.setState({password: e.target.value})}/>
|
||||||
|
</Form.Group> : null
|
||||||
|
}
|
||||||
|
|
||||||
<Form.Check
|
<Form.Check
|
||||||
type="switch"
|
type="switch"
|
||||||
id="custom-switch-2"
|
id="custom-switch-2"
|
||||||
@ -81,13 +91,18 @@ class GeneralSettings extends React.Component {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{this.state.passwordsupport ?
|
<Form.Check
|
||||||
<Form.Group data-testid="passwordfield">
|
type="switch"
|
||||||
<Form.Label>Password</Form.Label>
|
id="custom-switch-3"
|
||||||
<Form.Control type="password" placeholder="**********" value={this.state.password}
|
data-testid='darktheme-switch'
|
||||||
onChange={(e) => this.setState({password: e.target.value})}/>
|
label="Enable Dark-Theme"
|
||||||
</Form.Group> : null
|
checked={GlobalInfos.isDarkTheme()}
|
||||||
}
|
onChange={() => {
|
||||||
|
GlobalInfos.enableDarkTheme(!GlobalInfos.isDarkTheme());
|
||||||
|
this.forceUpdate();
|
||||||
|
// todo initiate rerender
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<Form.Group className={style.mediacenternameform} data-testid="nameform">
|
<Form.Group className={style.mediacenternameform} data-testid="nameform">
|
||||||
<Form.Label>The name of the Mediacenter</Form.Label>
|
<Form.Label>The name of the Mediacenter</Form.Label>
|
||||||
@ -113,6 +128,7 @@ class GeneralSettings extends React.Component {
|
|||||||
updateRequest.append('tvshowpath', this.state.tvshowpath);
|
updateRequest.append('tvshowpath', this.state.tvshowpath);
|
||||||
updateRequest.append('mediacentername', this.state.mediacentername);
|
updateRequest.append('mediacentername', this.state.mediacentername);
|
||||||
updateRequest.append("tmdbsupport", this.state.tmdbsupport);
|
updateRequest.append("tmdbsupport", this.state.tmdbsupport);
|
||||||
|
updateRequest.append("darkmodeenabled", GlobalInfos.isDarkTheme());
|
||||||
|
|
||||||
fetch('/api/Settings.php', {method: 'POST', body: updateRequest})
|
fetch('/api/Settings.php', {method: 'POST', body: updateRequest})
|
||||||
.then((response) => response.json()
|
.then((response) => response.json()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {shallow} from "enzyme";
|
import {shallow} from "enzyme";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import GeneralSettings from "./GeneralSettings";
|
import GeneralSettings from "./GeneralSettings";
|
||||||
|
import GlobalInfos from "../../GlobalInfos";
|
||||||
|
|
||||||
describe('<GeneralSettings/>', function () {
|
describe('<GeneralSettings/>', function () {
|
||||||
it('renders without crashing ', function () {
|
it('renders without crashing ', function () {
|
||||||
@ -17,6 +18,15 @@ describe('<GeneralSettings/>', function () {
|
|||||||
expect(wrapper.find("[data-testid='passwordfield']")).toHaveLength(1);
|
expect(wrapper.find("[data-testid='passwordfield']")).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('test theme switchbutton', function () {
|
||||||
|
const wrapper = shallow(<GeneralSettings/>);
|
||||||
|
|
||||||
|
GlobalInfos.enableDarkTheme(false);
|
||||||
|
expect(GlobalInfos.isDarkTheme()).toBe(false);
|
||||||
|
wrapper.find("[data-testid='darktheme-switch']").simulate("change");
|
||||||
|
expect(GlobalInfos.isDarkTheme()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('test savesettings', done => {
|
it('test savesettings', done => {
|
||||||
const wrapper = shallow(<GeneralSettings/>);
|
const wrapper = shallow(<GeneralSettings/>);
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import MovieSettings from "./MovieSettings";
|
import MovieSettings from "./MovieSettings";
|
||||||
import GeneralSettings from "./GeneralSettings";
|
import GeneralSettings from "./GeneralSettings";
|
||||||
import style from "./SettingsPage.module.css"
|
import style from "./SettingsPage.module.css"
|
||||||
|
import GlobalInfos from "../../GlobalInfos";
|
||||||
|
|
||||||
|
|
||||||
class SettingsPage extends React.Component {
|
class SettingsPage extends React.Component {
|
||||||
@ -27,10 +28,11 @@ class SettingsPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const themestyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className={style.SettingsSidebar}>
|
<div className={style.SettingsSidebar + ' ' + themestyle.secbackground}>
|
||||||
<div className={style.SettingsSidebarTitle}>Settings</div>
|
<div className={style.SettingsSidebarTitle + ' ' + themestyle.lighttextcolor}>Settings</div>
|
||||||
<div onClick={() => this.setState({currentpage: "general"})}
|
<div onClick={() => this.setState({currentpage: "general"})}
|
||||||
className={style.SettingSidebarElement}>General
|
className={style.SettingSidebarElement}>General
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
.SettingsSidebar {
|
.SettingsSidebar {
|
||||||
background-color: #d3dcef;
|
border-bottom-right-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
float: left;
|
float: left;
|
||||||
min-height: calc(100vh - 56px);
|
min-height: calc(100vh - 62px);
|
||||||
min-width: 110px;
|
min-width: 110px;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
width: 10%;
|
width: 10%;
|
||||||
@ -23,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.SettingSidebarElement {
|
.SettingSidebarElement {
|
||||||
background-color: #a8b2de;
|
background-color: #919fd9;
|
||||||
border-radius: 7px;
|
border-radius: 7px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 10px 5px 5px;
|
margin: 10px 5px 5px;
|
||||||
|
Loading…
Reference in New Issue
Block a user