Merge branch 'React' into 'master'

React

See merge request lukas/hub!1
This commit is contained in:
Lukas Heiligenbrunner 2020-06-01 15:10:14 +00:00
commit 8456a4aec4
29 changed files with 14762 additions and 513 deletions

View File

@ -1,47 +0,0 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>hub</title>
<link rel="stylesheet" href="css/plyr.css"/>
<link rel="stylesheet" href="css/index.css">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- Popper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@9"></script>
<script src="js/plyr.js"></script>
<script src="js/index.js"></script>
</head>
<body>
<!-- Grey with black text -->
<nav class="navbar navbar-expand-sm bg-primary navbar-dark">
<!-- Brand -->
<a class="navbar-brand" href="#">Lukis Tube</a>
<ul class="navbar-nav">
<li class="nav-item ">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="random.html">Random Video</a>
</li>
<li class="nav-item active">
<a class="nav-link" href="category.html">Categories</a>
</li>
</ul>
</nav>
</body>
</html>

View File

File diff suppressed because one or more lines are too long

View File

View File

@ -1,86 +0,0 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>hub</title>
<link rel="stylesheet" href="css/plyr.css"/>
<link rel="stylesheet" href="css/index.css">
<link rel="stylesheet" href="css/video.css">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- Popper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@9"></script>
<script src="js/plyr.js"></script>
<script src="js/index.js"></script>
</head>
<body>
<!-- Grey with black text -->
<nav class="navbar navbar-expand-sm bg-primary navbar-dark">
<!-- Brand -->
<a class="navbar-brand" href="#">Lukis Tube</a>
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="random.html">Random Video</a>
</li>
<li class="nav-item">
<a class="nav-link" href="category.html">Categories</a>
</li>
</ul>
</nav>
<div class="videopagewrapper hideit">
<div class="row">
<div class="col-sm-2">
<div class="videoleftbanner">
<div class="likefield">Likes: 10</div>
</div>
</div>
<div class="col-sm-8">
<div class="videowrapper"></div>
</div>
<div class="col-sm-2">
<div class="closebutton">Close</div>
<div class="videorightbanner"></div>
</div>
</div>
<div class="row">
<div class="col-sm-5">
</div>
<div class="col-sm-2">
<button id="likebtn">Like it!</button>
<button id="tagbutton">Tag it!</button>
</div>
<div class="col-sm-5">
</div>
</div>
</div>
<div class="previewcontainer">
</div>
</body>
</html>

View File

@ -1,130 +0,0 @@
let videos;
let loadindex = 0;
let scrollposition = 0;
let loadedvideoid = -1;
$(document).ready(function () {
$.post('php/videoload.php', 'action=getMovies', function (data) {
videos = data;
loadPreviewBlock(15);
}, 'json');
$.post('php/videoload.php', 'action=getDbSize', function (data) {
console.log(data);
}, 'json');
$(".closebutton").click(function () {
$("#likebtn").off();
$("#tagbutton").off();
$(".videopagewrapper").hide();
$(".previewcontainer").show();
// scroll back to last scroll position
$(window).scrollTop(scrollposition);
$(".videowrapper").html("");
});
});
$(window).scroll(function () {
if ($(window).scrollTop() >= (($(document).height() - $(window).height() - 60))) {
if ($(".videowrapper").html() === "") {
loadPreviewBlock(6);
}
}
});
function loadPreviewBlock(nr) {
for (let i = 0; i < nr; i++) {
if (loadindex + i < videos.length) {
loadPreview(videos[loadindex + i]);
}
}
loadindex += nr;
}
function loadPreview(src) {
$.post('php/videoload.php', 'action=readThumbnail&movieid=' + src.movie_id, function (data) {
var preview = $(`
<div class='videopreview'>
<div class='previewtitle'>${src.movie_name}</div>
<div class='previewpic'>
<img style='width:100%;height:100%' src="${data}" alt='no thumbnail found'/>
</div>
</div>`);
preview.attr('movie_id', src.movie_id);
preview.click(function () {
console.log("preview clicked");
scrollposition = $(window).scrollTop();
loadedvideoid = $(this).attr("movie_id");
loadVideo(loadedvideoid);
});
$(".previewcontainer").append(preview);
}, 'text');
}
function loadVideo(movieid) {
$.post('php/videoload.php', 'action=loadVideo&movieid=' + movieid, function (data) {
$(".videowrapper").html("<div class='myvideo'><video controls crossorigin playsinline id='player'></video></div>");
const player = new Plyr('#player');
player.source = {
type: 'video',
sources: [
{
src: data.movie_url,
type: 'video/mp4',
size: 1080,
}
],
poster: data.thumbnail
};
$(".likefield").html("Likes: " + data.likes);
$.post('php/videoload.php', 'action=getTags&movieid=' + loadedvideoid, function (data) {
for (const tag in data.tags) {
$(".videoleftbanner").append(`<div>${tag}</div>`);
}
console.log(data);
}, "json");
$("#likebtn").click(function () {
console.log("likebtn clicked");
$.post('php/videoload.php', 'action=addLike&movieid=' + loadedvideoid, function (data) {
console.log(data);
}, "json");
});
$("#tagbutton").click(function () {
console.log("tagbrn clicked");
Swal.mixin({
input: 'text',
confirmButtonText: 'Next &rarr;',
showCancelButton: true,
progressSteps: ['1', '2', '3']
}).queue([
{
title: 'Question 1',
text: 'Chaining swal2 modals is easy'
},
'Question 2',
'Question 3'
]).then((result) => {
if (result.value) {
const answers = JSON.stringify(result.value)
Swal.fire({
title: 'All done!',
html: `
Your answers:
<pre><code>${answers}</code></pre>
`,
confirmButtonText: 'Lovely!'
})
}
})
});
$(".videopagewrapper").show();
$(".previewcontainer").hide();
}, "json");
}

File diff suppressed because one or more lines are too long

View File

@ -1,125 +0,0 @@
let videos;
let loadindex = 0;
let loadedvideoid = -1;
$(document).ready(function () {
$.post('php/videoload.php', 'action=getRandomMovies&number=6', function (data) {
videos = data;
loadPreviewBlock(6);
}, 'json');
$(".closebutton").click(function () {
$("#likebtn").off();
$("#tagbutton").off();
$(".videopagewrapper").hide();
$(".previewcontainer").show();
// scroll back to last scroll position
$(window).scrollTop(scrollposition);
$(".videowrapper").html("");
});
$("#shufflebtn").click(function () {
$(".previewcontainer").html("");
$.post('php/videoload.php', 'action=getRandomMovies&number=6', function (data) {
videos = data;
loadPreviewBlock(6);
}, 'json');
});
});
function loadPreviewBlock(nr) {
for (let i = 0; i < nr; i++) {
if (loadindex + i < videos.length) {
loadPreview(videos[loadindex + i]);
}
}
loadindex += nr;
}
function loadPreview(src) {
$.post('php/videoload.php', 'action=readThumbnail&movieid=' + src.movie_id, function (data) {
var preview = $(`
<div class='videopreview'>
<div class='previewtitle'>${src.movie_name}</div>
<div class='previewpic'>
<img style='width:100%;height:100%' src="${data}" alt='no thumbnail found'/>
</div>
</div>`);
preview.attr('movie_id', src.movie_id);
preview.click(function () {
console.log("preview clicked");
scrollposition = $(window).scrollTop();
loadedvideoid = $(this).attr("movie_id");
loadVideo(loadedvideoid);
});
$(".previewcontainer").append(preview);
}, 'text');
}
function loadVideo(movieid) {
$.post('php/videoload.php', 'action=loadVideo&movieid=' + movieid, function (data) {
$(".videowrapper").html("<div class='myvideo'><video controls crossorigin playsinline id='player'></video></div>");
const player = new Plyr('#player');
player.source = {
type: 'video',
sources: [
{
src: data.movie_url,
type: 'video/mp4',
size: 1080,
}
],
poster: data.thumbnail
};
$(".likefield").html("Likes: " + data.likes);
$.post('php/videoload.php', 'action=getTags&movieid=' + loadedvideoid, function (data) {
for (const tag in data.tags) {
$(".videoleftbanner").append(`<div>${tag}</div>`);
}
console.log(data);
}, "json");
$("#likebtn").click(function () {
console.log("likebtn clicked");
$.post('php/videoload.php', 'action=addLike&movieid=' + loadedvideoid, function (data) {
console.log(data);
}, "json");
});
$("#tagbutton").click(function () {
console.log("tagbrn clicked");
Swal.mixin({
input: 'text',
confirmButtonText: 'Next &rarr;',
showCancelButton: true,
progressSteps: ['1', '2', '3']
}).queue([
{
title: 'Question 1',
text: 'Chaining swal2 modals is easy'
},
'Question 2',
'Question 3'
]).then((result) => {
if (result.value) {
const answers = JSON.stringify(result.value)
Swal.fire({
title: 'All done!',
html: `
Your answers:
<pre><code>${answers}</code></pre>
`,
confirmButtonText: 'Lovely!'
})
}
})
});
$(".videopagewrapper").show();
$(".previewcontainer").hide();
}, "json");
}

14053
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

37
package.json Normal file
View File

@ -0,0 +1,37 @@
{
"name": "untitled",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"bootstrap": "^4.5.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1",
"plyr-react": "2.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"proxy": "http://127.0.0.1:4000",
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

43
public/index.html Normal file
View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

BIN
public/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
public/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

25
public/manifest.json Normal file
View File

@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
public/robots.txt Normal file
View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@ -1,85 +0,0 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>hub</title>
<link rel="stylesheet" href="css/plyr.css"/>
<link rel="stylesheet" href="css/video.css">
<link rel="stylesheet" href="css/random.css">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- Popper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@9"></script>
<script src="js/plyr.js"></script>
<script src="js/random.js"></script>
</head>
<body>
<!-- Grey with black text -->
<nav class="navbar navbar-expand-sm bg-primary navbar-dark">
<!-- Brand -->
<a class="navbar-brand" href="#">Lukis Tube</a>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item active">
<a class="nav-link" href="random.html">Random Video</a>
</li>
<li class="nav-item">
<a class="nav-link" href="category.html">Categories</a>
</li>
</ul>
</nav>
<div class="videopagewrapper hideit">
<div class="row">
<div class="col-sm-2">
<div class="videoleftbanner">
<div class="likefield">Likes: 10</div>
</div>
</div>
<div class="col-sm-8">
<div class="videowrapper"></div>
</div>
<div class="col-sm-2">
<div class="closebutton">Close</div>
<div class="videorightbanner"></div>
</div>
</div>
<div class="row">
<div class="col-sm-5">
</div>
<div class="col-sm-2">
<button id="likebtn">Like it!</button>
<button id="tagbutton">Tag it!</button>
</div>
<div class="col-sm-5">
</div>
</div>
</div>
<div class="previewcontainer">
</div>
<div style="width: 100%"><button type="button" id="shufflebtn" class="btn btn-success">Shuffle</button></div>
</body>
</html>

71
src/App.js Normal file
View File

@ -0,0 +1,71 @@
import React from 'react';
import MainBody from "./MainBody";
import 'bootstrap/dist/css/bootstrap.min.css';
class App extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {page: "default"};
// bind this to the method for being able to call methods such as this.setstate
this.showVideo = this.showVideo.bind(this);
this.hideVideo = this.hideVideo.bind(this);
}
render() {
return (
<div className="App">
<nav className="navbar navbar-expand-sm bg-primary navbar-dark">
<a className="navbar-brand" href="!#">Lukis Tube</a>
<ul className="navbar-nav">
<li className="nav-item">
<a className="nav-link" onClick={() => this.loadHomePage()} href='# '>Home</a>
</li>
<li className="nav-item">
<a className="nav-link" onClick={() => this.loadRandomPage()} href="# ">Random Video</a>
</li>
<li className="nav-item">
<a className="nav-link" onClick={() => this.loadCategoriesPage()} href="# ">Categories</a>
</li>
</ul>
</nav>
<MainBody viewbinding={{showVideo: this.showVideo, hideVideo: this.hideVideo}} page={this.state.page}
videoelement={this.element}/>
</div>
);
}
loadCategoriesPage() {
console.log("click categories");
this.setState({page: "categories"});
}
loadRandomPage() {
console.log("click random");
this.setState({page: "random"});
}
loadHomePage() {
console.log("click default");
this.setState({page: "default"});
}
showVideo(element) {
this.setState({
page: "video"
});
this.element = element;
}
hideVideo() {
this.setState({
page: "default"
});
this.element = null;
}
}
export default App;

91
src/HomePage.js Normal file
View File

@ -0,0 +1,91 @@
import React from "react";
import Preview from "./Preview";
import "./css/HomePage.css"
class HomePage extends React.Component {
// stores all available movies
data = null;
// stores current index of loaded elements
loadindex = 0;
constructor(props, context) {
super(props, context);
this.state = {
loadeditems: []
};
}
componentDidMount() {
document.addEventListener('scroll', this.trackScrolling);
const updateRequest = new FormData();
updateRequest.append('action', 'getMovies');
// fetch all videos available
fetch('/php/videoload.php', {method: 'POST', body: updateRequest})
.then((response) => response.json())
.then((result) => {
this.data = result;
this.loadPreviewBlock(12);
});
}
componentWillUnmount() {
this.setState({});
document.removeEventListener('scroll', this.trackScrolling);
}
render() {
return (
<div>
<div><h1>Home page</h1></div>
<div className='sideinfo'>
beep beep
</div>
<div className='maincontent'>
{this.state.loadeditems.map(elem => (
<Preview
key={elem.movie_id}
name={elem.movie_name}
movie_id={elem.movie_id}
viewbinding={this.props.viewbinding}/>
))}
</div>
<div className='rightinfo'>
</div>
</div>
);
}
loadPreviewBlock(nr) {
console.log("loadpreviewblock called ...")
let ret = [];
for (let i = 0; i < nr; i++) {
// only add if not end
if (this.data.length > this.loadindex + i) {
ret.push(this.data[this.loadindex + i]);
}
}
this.setState({
loadeditems: [
...this.state.loadeditems,
...ret
]
});
this.loadindex += nr;
}
trackScrolling = (e) => {
if (window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight) {
this.loadPreviewBlock(6);
}
}
}
export default HomePage;

24
src/MainBody.js Normal file
View File

@ -0,0 +1,24 @@
import React from "react";
import HomePage from "./HomePage";
class MainBody extends React.Component {
constructor(props) {
super(props);
this.props = props;
}
render() {
let page;
if (this.props.page === "default") {
page = <HomePage viewbinding={this.props.viewbinding}/>;
} else if (this.props.page === "video") {
// show videoelement if neccessary
page = this.props.videoelement;
} else {
page = <div>unimplemented yet!</div>;
}
return (page);
}
}
export default MainBody;

128
src/Player.js Normal file
View File

@ -0,0 +1,128 @@
import React from "react";
import "./css/Player.css"
import {PlyrComponent} from 'plyr-react';
class Player extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {};
this.props = props;
}
options = {
controls: [
'play-large', // The large play button in the center
'play', // Play/pause playback
'progress', // The progress bar and scrubber for playback and buffering
'current-time', // The current time of playback
'duration', // The full duration of the media
'mute', // Toggle mute
'volume', // Volume control
'captions', // Toggle captions
'settings', // Settings menu
'airplay', // Airplay (currently Safari only)
'download', // Show a download button with a link to either the current source or a custom URL you specify in your options
'fullscreen', // Toggle fullscreen
]
};
componentDidMount() {
this.fetchMovieData();
}
render() {
return (
<div>
<div className="row">
<div className="col-sm-2">
<div className="videoleftbanner">
<div className="likefield">Likes: {this.state.likes}</div>
</div>
</div>
<div className="col-sm-8">
<div className="videowrapper">
<div className='myvideo'>
{this.state.sources ? <PlyrComponent
sources={this.state.sources}
options={this.options}/> :
<div>not loaded yet</div>}
</div>
</div>
</div>
<div className="col-sm-2">
<div className="closebutton" onClick={() => {this.closebtn()}}>Close</div>
<div className="videorightbanner"></div>
</div>
</div>
<div className="row">
<div className="col-sm-5">
</div>
<div className="col-sm-2">
<button className='btn btn-primary' onClick={() => {this.likebtn()}}>Like it!</button>
<button className='btn btn-info' id="tagbutton">Tag it!</button>
</div>
<div className="col-sm-5">
</div>
</div>
</div>
);
}
fetchMovieData(){
const updateRequest = new FormData();
updateRequest.append('action', 'loadVideo');
updateRequest.append('movieid', this.props.movie_id);
fetch('/php/videoload.php', {method: 'POST', body: updateRequest})
.then((response) => response.json())
.then((result) => {
this.setState({
sources: {
type: 'video',
sources: [
{
src: result.movie_url,
type: 'video/mp4',
size: 1080,
}
],
poster: result.thumbnail
},
likes: result.likes
});
});
}
/* Click Listener */
likebtn() {
const updateRequest = new FormData();
updateRequest.append('action', 'addLike');
updateRequest.append('movieid', this.props.movie_id);
fetch('/php/videoload.php', {method: 'POST', body: updateRequest})
.then((response) => response.json())
.then((result) => {
if(result.result === "success"){
this.fetchMovieData();
}else{
console.log("an error occured while liking");
console.log(result);
}
});
}
closebtn() {
this.props.viewbinding.hideVideo();
}
}
export default Player;

59
src/Preview.js Normal file
View File

@ -0,0 +1,59 @@
import React from "react";
import "./css/Preview.css"
import Player from "./Player";
class Preview extends React.Component {
constructor(props, context) {
super(props, context);
this.props = props;
this.state = {
previewpicture: null,
name: null
};
}
componentWillUnmount() {
this.setState({});
}
componentDidMount() {
this.setState({
previewpicture: null,
name: this.props.name
});
const updateRequest = new FormData();
updateRequest.append('action', 'readThumbnail');
updateRequest.append('movieid', this.props.movie_id);
fetch('/php/videoload.php', {method: 'POST', body: updateRequest})
.then((response) => response.text())
.then((result) => {
this.setState(prevState => ({
...prevState.previewpicture, previewpicture: result
}));
});
}
render() {
return (
<div className='videopreview' onClick={() => this.itemClick()}>
<div className='previewtitle'>{this.state.name}</div>
<div className='previewpic'>
<img className='previewimage'
src={this.state.previewpicture}
alt='no thumbnail found'/>
</div>
</div>
);
}
itemClick() {
console.log("item clicked!" + this.state.name);
this.props.viewbinding.showVideo(<Player viewbinding={this.props.viewbinding} movie_id={this.props.movie_id}/>);
}
}
export default Preview;

14
src/css/HomePage.css Normal file
View File

@ -0,0 +1,14 @@
.sideinfo{
width: 20%;
float: left;
}
.maincontent{
float: left;
width: 70%;
}
.rightinfo{
float: left;
width: 10%;
}

View File

@ -1,7 +1,3 @@
.hideit {
display: none;
}
.closebutton {
color: white;
height: 35px;
@ -35,36 +31,3 @@
color: white;
}
.previewcontainer {
margin-left: 10%;
width: 80%;
margin-right: 10%;
}
.videopreview {
height: 300px;
width: 30%;
float: left;
margin: 1%;
background-color: #7F7F7F;
cursor: pointer;
opacity: 0.9;
border: 10px;
border-radius: 20px;
}
.videopreview:hover {
opacity: 1;
transition: opacity 0.5s;
}
.previewtitle {
height: 10%;
color: white;
text-align: center;
}
.previewpic {
height: 80%;
}

38
src/css/Preview.css Normal file
View File

@ -0,0 +1,38 @@
.previewtitle {
height: 10%;
color: white;
text-align: center;
}
.previewpic {
height: 80%;
}
.previewimage{
width:100%;
height:100%;
}
.videopreview {
height: 300px;
width: 30%;
float: left;
margin: 1%;
background-color: #7F7F7F;
cursor: pointer;
opacity: 0.9;
border: 10px;
border-radius: 20px;
}
.videopreview:hover {
opacity: 1;
transition: opacity 0.5s;
}
/* todo check if neccessary*/
.previewcontainer {
margin-left: 10%;
width: 80%;
margin-right: 10%;
}

13
src/css/index.css Normal file
View File

@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

17
src/index.js Normal file
View File

@ -0,0 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './css/index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.register();

141
src/serviceWorker.js Normal file
View File

@ -0,0 +1,141 @@
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, {
headers: { 'Service-Worker': 'script' },
})
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready
.then(registration => {
registration.unregister();
})
.catch(error => {
console.error(error.message);
});
}
}

5
src/setupTests.js Normal file
View File

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect';