Implementing bootstrap

Navbar partially completed, may tweak

StatCards on home page has been somewhat unified, will need to figure out how to use boot strap to make it look like the cards on main branch

Bootstrap applied to settings page(still not finalized on a design)
This commit is contained in:
Thegan Govender
2023-04-08 19:38:34 +02:00
parent 590ae82f85
commit 15584fbfb9
31 changed files with 664 additions and 451 deletions

View File

@@ -17,14 +17,15 @@ main{
body
{
background-color: #1e1c22;
background-color: #1e1c22 !important;
/* background-color: #17151a; */
color: white;
}
h1{
color: white;
font-weight: lighter;
margin: 0;
font-weight: lighter !important;
margin: 0 !important;
margin-top: 0.5em;
margin-bottom: 0.5em;
}

View File

@@ -4,7 +4,7 @@ import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(

View File

@@ -83,7 +83,7 @@ function Activity() {
}
return (
<div>
<div className="Activity">
<div className="Heading">
<h1>Activity</h1>
<div className="pagination-range">

View File

@@ -1,5 +1,8 @@
import React, { useState } from "react";
import Row from 'react-bootstrap/Row';
import MVLibraries from "./statCards/mv_libraries";
import MVMovies from "./statCards/mv_movies";
import MVSeries from "./statCards/mv_series";
@@ -48,7 +51,38 @@ function HomeStatisticCards() {
</div>
<div className="stat-cards-container">
<Row xs={1} sm={2} md={3} lg={4} xl={5} className="g-4">
<MVMovies days={days} />
<MPMovies days={days} />
<MVSeries days={days} />
<MPSeries days={days} />
<MVMusic days={days}/>
<MPMusic days={days}/>
<MVLibraries days={days} />
<MostUsedClient days={days} />
<MostActiveUsers days={days} />
</Row>
{/* <div className="card-group">
<MVMovies days={days} />
<MPMovies days={days} />
<MVSeries days={days} />
@@ -59,7 +93,7 @@ function HomeStatisticCards() {
<MostUsedClient days={days} />
<MostActiveUsers days={days} />
</div>
</div> */}
</div>
);
}

View File

@@ -1,7 +1,8 @@
import { NavLink } from "react-router-dom";
import { Nav, Navbar as BootstrapNavbar, Container, Col } from "react-bootstrap";
import { Link, useLocation } from "react-router-dom";
import { navData } from "../../../lib/navdata";
import "../../css/navbar.css";
import LogoutBoxLineIcon from "remixicon-react/LogoutBoxLineIcon";
import "../../css/navbar.css";
export default function Navbar() {
const handleLogout = () => {
@@ -9,23 +10,42 @@ export default function Navbar() {
window.location.reload();
};
const location = useLocation(); // use the useLocation hook from react-router-dom
return (
<div className={"navbar"}>
<h1 style={{marginRight:"20px"}}>Jellystat</h1>
{navData.map((item) => {
return (
<NavLink key={item.id} className={"navitem"} to={item.link}>
{item.icon}
<span className={"nav-text"}>{item.text}</span>
</NavLink>
);
})}
<NavLink className={"navitem"} to={"/logout"} onClick={handleLogout}>
<LogoutBoxLineIcon />
<span className={"nav-text"}>Logout</span>
</NavLink>
</div>
<BootstrapNavbar variant="dark" expand="md" className="navbar py-0">
<Container fluid>
<Col xs={8} md={4}>
<BootstrapNavbar.Brand href="#home">Jellystat</BootstrapNavbar.Brand>
</Col>
<Col className="d-flex align-items-center justify-content-end">
<BootstrapNavbar.Toggle aria-controls="basic-navbar-nav" />
</Col>
<Col md={8} className="w-100">
<BootstrapNavbar.Collapse id="basic-navbar-nav">
<Nav className="ml-auto">
{navData.map((item) => {
const isActive = ('/'+item.link).toLocaleLowerCase() === location.pathname.toLocaleLowerCase(); // check if the link is the current path
return (
<Nav.Link
as={Link}
key={item.id}
className={`navitem${isActive ? " active" : ""}`} // add the "active" class if the link is active
to={item.link}
>
{item.icon}
<span className="nav-text">{item.text}</span>
</Nav.Link>
);
})}
<Nav.Link className="navitem" href="#logout" onClick={handleLogout}>
<LogoutBoxLineIcon />
<span className="nav-text">Logout</span>
</Nav.Link>
</Nav>
</BootstrapNavbar.Collapse>
</Col>
</Container>
</BootstrapNavbar>
);
}

View File

@@ -32,8 +32,7 @@ const TerminalComponent = () => {
}, [messages]);
return (
<div>
<h1>Terminal</h1>
<div className='my-4'>
<div className="console-container">
{messages.map((message, index) => (
<div key={index} className="console-message">

View File

@@ -1,5 +1,9 @@
import React, { useState } from "react";
import axios from "axios";
import Button from "react-bootstrap/Button";
import Form from 'react-bootstrap/Form';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import "../../css/settings.css";
@@ -39,7 +43,18 @@ export default function LibrarySync() {
return (
<div className="settings-form">
<button style={{backgroundColor: !processing? '#2196f3':'darkgrey',cursor: !processing? 'pointer':'default' }} disabled={processing} onClick={handleClick}>Run Sync</button>
<h1 className="my-2">Tasks</h1>
<Row className="mb-3" controlId="form_task_sync">
<Form.Label column sm="2">
Syncronize with Jellyfin
</Form.Label>
<Col sm="10">
<Button variant={!processing ? "outline-primary" : "outline-light"} disabled={processing} onClick={handleClick}>Run Sync</Button>
</Col>
</Row>
</div>
);

View File

@@ -2,10 +2,15 @@ import React, { useState, useEffect } from "react";
import axios from "axios";
import Config from "../../../lib/config";
import Loading from "../general/loading";
import Form from 'react-bootstrap/Form';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Button from 'react-bootstrap/Button';
import "../../css/settings.css";
import { ButtonGroup } from "react-bootstrap";
export default function SettingsConfig() {
const [config, setConfig] = useState(null);
@@ -79,8 +84,6 @@ export default function SettingsConfig() {
}
setisSubmitted("");
// Send a POST request to /api/setconfig/ with the updated configuration
axios
.post("/api/setconfig/", formValues, {
headers: {
@@ -117,29 +120,24 @@ export default function SettingsConfig() {
return (
<div className="general-settings-page">
<h1>General Settings</h1>
<form onSubmit={handleFormSubmit} className="settings-form">
<div className="form-row">
<label htmlFor="JF_HOST">Jellyfin URL</label>
<input
type="text"
id="JF_HOST"
name="JF_HOST"
value={formValues.JF_HOST || ""}
onChange={handleFormChange}
/>
</div>
<div className="form-row">
<label htmlFor="JF_API_KEY">API Key</label>
<input
type={showKey ? "text" : "password"}
id="JF_API_KEY"
name="JF_API_KEY"
value={formValues.JF_API_KEY || ""}
onChange={handleFormChange}
/>
<button className="show-key" type="button" onClick={() => setKeyState(!showKey)}>Show Key</button>
</div>
<Form onSubmit={handleFormSubmit} className="settings-form">
<Form.Group as={Row} className="mb-3" controlId="form_jellyfin_url">
<Form.Label column className="fs-4">
Jellyfin Url
</Form.Label>
<Col sm="10">
<Form.Control id="JF_HOST" name="JF_HOST" value={formValues.JF_HOST || ""} onChange={handleFormChange} placeholder="http://127.0.0.1:8096 or http://example.jellyfin.server" />
</Col>
</Form.Group>
<Form.Group as={Row} className="mb-3" controlId="form_api_key">
<Form.Label column className="fs-4">
API Key
</Form.Label>
<Col sm="10">
<Form.Control id="JF_API_KEY" value={formValues.JF_API_KEY || ""} onChange={handleFormChange} type={showKey ? "text" : "password"} />
</Col>
</Form.Group>
{isSubmitted !== "" ? (
<div
className={
@@ -151,9 +149,14 @@ export default function SettingsConfig() {
) : (
<></>
)}
<button className="settings-submit-button" type="submit">Save</button>
</form>
<div className="d-flex flex-column flex-sm-row justify-content-end align-items-sm-center">
<ButtonGroup >
<Button variant="outline-success" type="submit"> Save </Button>
<Button variant="outline-secondary" type="button" onClick={() => setKeyState(!showKey)}>Show Key</Button>
</ButtonGroup>
</div>
</Form>
</div>
);

View File

@@ -0,0 +1,92 @@
import React, {useState} from "react";
import { Blurhash } from 'react-blurhash';
import { Link } from "react-router-dom";
import Card from 'react-bootstrap/Card';
function ItemStatComponent(props) {
const [loaded, setLoaded] = useState(false);
const handleImageLoad = () => {
setLoaded(true);
}
const cardStyle = {
backgroundImage: `url(${props.base_url}/Items/${props.data[0].Id}/Images/Backdrop/?fillWidth=300&quality=10), linear-gradient(to right, #00A4DC, #AA5CC3)`,
height:'100%',
backgroundSize: 'cover',
};
const cardBgStyle = {
backdropFilter: 'blur(10px)',
backgroundColor: 'rgb(0, 0, 0, 0.6)',
height:'100%',
};
return (
<Card style={cardStyle}>
<div style={cardBgStyle} >
{props.icon ?
<div className="stat-card-image">
{props.icon}
</div>
:
<>
{!loaded && (
<div className="position-absolute w-100 h-100">
<Blurhash hash={props.data[0].PrimaryImageHash} width="100%" height="100%" />
</div>
)}
<Card.Img
variant="top"
className="stat-card-image"
src={props.base_url + "/Items/" + props.data[0].Id + "/Images/Primary?fillWidth=400&quality=90"}
style={{ display: loaded ? 'block' : 'none' }}
onLoad={handleImageLoad}
onError={() => setLoaded(false)}
/>
</>
}
<Card.Body className="px-1">
<Card.Header className="d-flex justify-content-between border-0 bg-transparent">
<div>
<Card.Subtitle className="stat-items">{props.heading}</Card.Subtitle>
</div>
<div>
<Card.Subtitle className="stat-items">{props.units}</Card.Subtitle>
</div>
</Card.Header>
{props.data &&
props.data.map((item, index) => (
<div className="d-flex justify-content-between p-1 stat-items" key={item.Id || index}>
<div className="d-flex justify-content-between" key={item.Id || index}>
<Card.Text className="stat-item-index">{index + 1}</Card.Text>
{item.UserId ?
<Link to={`/users/${item.UserId}`}>
<Card.Text>{item.Name}</Card.Text>
</Link>
:
<Card.Text>{item.Name || item.Client}</Card.Text>
}
</div>
<Card.Text className="stat-item-count">
{item.Plays || item.unique_viewers}
</Card.Text>
</div>
))}
</Card.Body>
</div>
</Card>
);
}
export default ItemStatComponent;

View File

@@ -0,0 +1,92 @@
import React, {useState} from "react";
import { Blurhash } from 'react-blurhash';
import { Link } from "react-router-dom";
import Card from 'react-bootstrap/Card';
function ItemStatComponent(props) {
const [loaded, setLoaded] = useState(false);
const handleImageLoad = () => {
setLoaded(true);
}
const cardStyle = {
backgroundImage: `url(${props.base_url}/Items/${props.data[0].Id}/Images/Backdrop/?fillWidth=300&quality=10), linear-gradient(to right, #00A4DC, #AA5CC3)`,
height:'100%',
backgroundSize: 'cover',
};
const cardBgStyle = {
backdropFilter: 'blur(10px)',
backgroundColor: 'rgb(0, 0, 0, 0.6)',
height:'100%',
};
return (
<Card style={cardStyle}>
<div style={cardBgStyle} >
{props.icon ?
<div className="stat-card-image">
{props.icon}
</div>
:
<>
{!loaded && (
<div className="position-absolute w-100 h-100">
<Blurhash hash={props.data[0].PrimaryImageHash} width="100%" height="100%" />
</div>
)}
<Card.Img
variant="top"
className="stat-card-image"
src={props.base_url + "/Items/" + props.data[0].Id + "/Images/Primary?fillWidth=400&quality=90"}
style={{ display: loaded ? 'block' : 'none' }}
onLoad={handleImageLoad}
onError={() => setLoaded(false)}
/>
</>
}
<Card.Body className="px-1">
<Card.Header className="d-flex justify-content-between border-0 bg-transparent">
<div>
<Card.Subtitle className="stat-items">{props.heading}</Card.Subtitle>
</div>
<div>
<Card.Subtitle className="stat-items">{props.units}</Card.Subtitle>
</div>
</Card.Header>
{props.data &&
props.data.map((item, index) => (
<div className="d-flex justify-content-between p-1 stat-items" key={item.Id || index}>
<div className="d-flex justify-content-between" key={item.Id || index}>
<Card.Text className="stat-item-index">{index + 1}</Card.Text>
{item.UserId ?
<Link to={`/users/${item.UserId}`}>
<Card.Text>{item.Name}</Card.Text>
</Link>
:
<Card.Text>{item.Name || item.Client}</Card.Text>
}
</div>
<Card.Text className="stat-item-count">
{item.Plays || item.unique_viewers}
</Card.Text>
</div>
))}
</Card.Body>
</div>
</Card>
);
}
export default ItemStatComponent;

View File

@@ -1,8 +1,8 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import Config from "../../../lib/config";
import StatComponent from "./statsComponent";
import ItemStatComponent from "./ItemStatComponent";
import Col from 'react-bootstrap/Col';
import AccountCircleFillIcon from "remixicon-react/AccountCircleFillIcon";
@@ -10,7 +10,7 @@ import AccountCircleFillIcon from "remixicon-react/AccountCircleFillIcon";
function MostActiveUsers(props) {
const [data, setData] = useState();
const [days, setDays] = useState(30);
const [imgError, setImgError] = useState(false);
// const [imgError, setImgError] = useState(false);
const [config, setConfig] = useState(null);
@@ -68,9 +68,9 @@ function MostActiveUsers(props) {
const handleImageError = () => {
setImgError(true);
};
// const handleImageError = () => {
// setImgError(true);
// };
if (!data || data.length === 0) {
@@ -79,31 +79,9 @@ function MostActiveUsers(props) {
return (
<div className="stats-card"
>
<div className="popular-image popular-user-image-container">
{imgError ?
<AccountCircleFillIcon size={'80%'}/>
:
<img
className="popular-user-image"
src={
config.hostUrl +
"/Users/" +
(data[0].UserId) +
"/Images/Primary?quality=50"
}
onError={handleImageError}
alt=""
></img>
}
</div>
<StatComponent data={data} heading={"MOST ACTIVE USERS"} units={"Plays"}/>
</div>
<Col>
<ItemStatComponent base_url={config.hostUrl} icon={<AccountCircleFillIcon color="white" size={"100%"}/>} data={data} heading={"MOST ACTIVE USERS"} units={"Plays"}/>
</Col>
);
}

View File

@@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import StatComponent from "./statsComponent";
import Col from 'react-bootstrap/Col';
import ItemStatComponent from "./ItemStatComponent";
@@ -53,17 +53,9 @@ function MostUsedClient(props) {
return (
<div className="stats-card"
>
<div className="popular-image">
<div className="library-icons">
<ComputerLineIcon size={'80%'}/>
</div>
</div>
<StatComponent data={data} heading={"MOST USED CLIENTS"} units={"Plays"}/>
</div>
<Col>
<ItemStatComponent icon={ <ComputerLineIcon color="white" size={'100%'}/>} data={data} heading={"MOST USED CLIENTS"} units={"Plays"}/>
</Col>
);
}

View File

@@ -1,10 +1,12 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import ItemImage from "./ItemImageComponent";
import Col from 'react-bootstrap/Col';
import Config from "../../../lib/config";
import StatComponent from "./statsComponent";
import ItemStatComponent from "./ItemStatComponent";
import Loading from "../general/loading";
function MPMovies(props) {
const [data, setData] = useState();
@@ -68,21 +70,15 @@ function MPMovies(props) {
return <></>;
}
return (
<div className="stats-card"
style={{
backgroundImage: `url(${
config.hostUrl +
"/Items/" +
(data[0].Id) +
"/Images/Backdrop/?fillWidth=300&quality=10"
})`}}
>
<ItemImage data={data[0]} base_url={config.hostUrl}/>
<StatComponent data={data} heading={"MOST POPULAR MOVIES"} units={"Users"}/>
if(!config)
{
return <Loading/>;
}
</div>
return (
<Col>
<ItemStatComponent base_url={config.hostUrl} data={data} heading={"MOST POPULAR MOVIES"} units={"Users"}/>
</Col>
);
}

View File

@@ -1,10 +1,10 @@
import React, { useState, useEffect } from "react";
import ItemImage from "./ItemImageComponent";
import axios from "axios";
import Config from "../../../lib/config";
import Col from 'react-bootstrap/Col';
import StatComponent from "./statsComponent";
import ItemStatComponent from "./ItemStatComponent";
@@ -70,21 +70,9 @@ function MPMusic(props) {
return (
<div className="stats-card"
style={{
backgroundImage: `url(${
config.hostUrl +
"/Items/" +
(data[0].Id) +
"/Images/Backdrop/?fillWidth=300&quality=10"
})`}}
>
<ItemImage data={data[0]} base_url={config.hostUrl}/>
<StatComponent data={data} heading={"MOST POPULAR MUSIC"} units={"Users"}/>
</div>
<Col>
<ItemStatComponent base_url={config.hostUrl} data={data} heading={"MOST POPULAR MUSIC"} units={"Users"}/>
</Col>
);
}

View File

@@ -1,9 +1,8 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import Config from "../../../lib/config";
import ItemImage from "./ItemImageComponent";
import StatComponent from "./statsComponent";
import ItemStatComponent from "./ItemStatComponent";
import Col from 'react-bootstrap/Col';
function MPSeries(props) {
@@ -68,21 +67,9 @@ function MPSeries(props) {
return (
<div className="stats-card"
style={{
backgroundImage: `url(${
config.hostUrl +
"/Items/" +
(data[0].Id) +
"/Images/Backdrop/?fillWidth=300&quality=10"
})`}}
>
<ItemImage data={data[0]} base_url={config.hostUrl}/>
<StatComponent data={data} heading={"MOST POPULAR SERIES"} units={"Users"}/>
</div>
<Col>
<ItemStatComponent base_url={config.hostUrl} data={data} heading={"MOST POPULAR SERIES"} units={"Users"}/>
</Col>
);
}

View File

@@ -1,7 +1,8 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import Col from 'react-bootstrap/Col';
import StatComponent from "./statsComponent";
import ItemStatComponent from "./ItemStatComponent";
import TvLineIcon from "remixicon-react/TvLineIcon";
import FilmLineIcon from "remixicon-react/FilmLineIcon";
@@ -52,24 +53,9 @@ function MVLibraries(props) {
return (
<div className="stats-card"
>
<div className="popular-image">
<div className="library-icons">
{data[0].CollectionType==="tvshows" ?
<TvLineIcon size={'80%'}/>
:
<FilmLineIcon size={'80%'}/>
}
</div>
</div>
<StatComponent data={data} heading={"MOST VIEWED LIBRARIES"} units={"Plays"}/>
</div>
<Col>
<ItemStatComponent icon={data[0].CollectionType==="tvshows"? <TvLineIcon color="white" size={'100%'}/> : <FilmLineIcon color="white" size={'100%'}/> } data={data} heading={"MOST VIEWED LIBRARIES"} units={"Plays"}/>
</Col>
);
}

View File

@@ -1,11 +1,11 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import ItemImage from "./ItemImageComponent";
import Config from "../../../lib/config";
import Col from 'react-bootstrap/Col';
import StatComponent from "./statsComponent";
import ItemStatComponent from "./ItemStatComponent";
function MVMusic(props) {
@@ -74,21 +74,9 @@ function MVMusic(props) {
return (
<div className="stats-card"
style={{
backgroundImage: `url(${
config.hostUrl +
"/Items/" +
(data[0].Id) +
"/Images/Backdrop/?fillWidth=300&quality=10"
})`}}
>
<ItemImage data={data[0]} base_url={config.hostUrl}/>
<StatComponent data={data} heading={"MOST VIEWED MOVIES"} units={"Plays"}/>
</div>
<Col>
<ItemStatComponent base_url={config.hostUrl} data={data} heading={"MOST VIEWED MOVIES"} units={"Plays"}/>
</Col>
);
}

View File

@@ -1,11 +1,8 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import Config from "../../../lib/config";
import ItemImage from "./ItemImageComponent";
import StatComponent from "./statsComponent";
import ItemStatComponent from "./ItemStatComponent";
import Col from 'react-bootstrap/Col';
function MVMovies(props) {
const [data, setData] = useState();
const [days, setDays] = useState(30);
@@ -71,21 +68,9 @@ function MVMovies(props) {
return (
<div className="stats-card"
style={{
backgroundImage: `url(${
config.hostUrl +
"/Items/" +
(data[0].Id) +
"/Images/Backdrop/?fillWidth=300&quality=10"
})`}}
>
<ItemImage data={data[0]} base_url={config.hostUrl}/>
<StatComponent data={data} heading={"MOST PLAYED MUSIC"} units={"Plays"}/>
</div>
<Col>
<ItemStatComponent base_url={config.hostUrl} data={data} heading={"MOST LISTENED MUSIC"} units={"Plays"}/>
</Col>
);
}

View File

@@ -1,9 +1,9 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import Config from "../../../lib/config";
import ItemImage from "./ItemImageComponent";
import Col from 'react-bootstrap/Col';
import StatComponent from "./statsComponent";
import ItemStatComponent from "./ItemStatComponent";
function MVSeries(props) {
@@ -69,21 +69,10 @@ function MVSeries(props) {
return (
<div className="stats-card"
style={{
backgroundImage: `url(${
config.hostUrl +
"/Items/" +
(data[0].Id) +
"/Images/Backdrop/?fillWidth=300&quality=10"
})`}}
>
<Col>
<ItemStatComponent base_url={config.hostUrl} data={data} heading={"MOST VIEWED SERIES"} units={"Plays"}/>
</Col>
<ItemImage data={data[0]} base_url={config.hostUrl}/>
<StatComponent data={data} heading={"MOST VIEWED SERIES"} units={"Plays"}/>
</div>
);
}

View File

@@ -1,57 +1,3 @@
.Activity
{
border-radius: 5px;
}
.Activity ul
{
list-style-type: none !important;
color: white;
width: fit-content;
}
.ActivityDetail
{
font-size: 1em;
padding-bottom: 5px;
}
.ActivityTime
{
/* text-align: right; */
font-size: small;
font-style: italic;
color: lightgray;
}
ul{
margin: 0;
padding: 0;
}
li.old {
opacity: 1;
transition: opacity 0.5s ease-in-out;
animation-name: fade-out;
animation-duration: 0.5s;
animation-fill-mode: forwards;
animation-delay: 0s;
}
li.new {
/* border: 2px solid grey; */
border-radius: 5px;
padding:10px 10px;
margin:10px 10px 0px 0px;
opacity: 0;
transition: opacity 1s ease-in-out;
animation-name: fade-in;
animation-duration: 1s;
animation-fill-mode: forwards;
animation-delay: 0s;
background-color: rgba(0, 0, 0, 0.4);
}
.Activity{
margin-top: 10px;
}

View File

@@ -17,6 +17,7 @@ div a
.activity-table
{
background-color: rgba(100,100, 100, 0.2);
color: white;
}

View File

@@ -1,5 +1,6 @@
.libraries-container
{
color: white;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));

View File

@@ -1,10 +1,10 @@
.navbar {
display: flex;
/* display: flex;
justify-content: flex-end;
align-items: center;
align-items: center; */
background-color: #5a2da5;
/* background: linear-gradient(to right, #AA5CC3,#00A4DC); */
height: 50px;
/* height: 50px; */
/* position: sticky;
top: 0; */
}
@@ -33,6 +33,7 @@
transition: background-color 0.2s ease-in-out;
}
.navitem:hover {
/* background-color: #326aa541; */
background-color: rgba(0,0,0,0.4);

View File

@@ -8,7 +8,8 @@
.settings-form {
color: white;
width: 100%;
/* width: 100%; */
margin-top: 20px;
}
@@ -56,9 +57,9 @@
margin-bottom: 10px;
} */
.settings-form button:hover {
/* .settings-form button:hover {
background-color: #0d8bf2;
}
} */
.submit
{

View File

@@ -0,0 +1,193 @@
.watch-stats
{
}
.Heading
{
display: flex;
margin-bottom: 10px;
}
.Heading h1
{
padding-right: 10px;
/* margin: 0; */
}
.stat-cards-container
{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(520px, 520px));
grid-auto-rows: 200px;/* max-width+offset so 215 + 20*/
margin-right: 20px;
margin-top: 4px;
}
.stats-card
{
width: 500px;
height: 180px;
display: flex;
color: white;
/* box-shadow: 0 0 20px 5px rgba(0, 0, 0, 0.5); */
background: linear-gradient(to right, #00A4DC, #AA5CC3);
background-size: cover;
border-radius: 4px;
}
.library-icons
{
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.stats-header {
display: flex;
justify-content: space-between;
color: white;
font-weight: 500;
}
.stats-header-plays {
color: lightgray;
font-weight: 300;
}
.stat-item {
display: flex;
justify-content: space-between;
width: 100%;
height: 20px;
margin-bottom: 5px;
}
.stat-item-index {
padding-top: 6px;
font-size: 0.8em;
padding-right: 2px;
color: grey;
text-align: right;
}
.stat-item-name {
width: 85%;
}
.stat-item-count {
width: 10%;
text-align: right;
color: #00A4DC;
font-weight: 500;
font-size: 1.1em;
}
.popular-image
{
height: 180px;
width: 175px;
background-color: rgb(0, 0, 0, 0.6);
border-radius:4px 0 0 4px;
}
.popular-banner-image
{
border-radius:4px 0 0 4px;
height: 180px;
width: 120px;
}
.popular-user-image-container
{
display: flex;
justify-content: center;
align-items: center;
}
.popular-user-image
{
border-radius: 50%;
width: 80%;
object-fit: cover;
}
.stats{
width: 100%;
padding: 5px 20px;
backdrop-filter: blur(4px);
border-radius: 0 4px 4px 0 ;
background-color: rgb(0, 0, 0, 0.6);
}
.date-range
{
width: 220px;
height: 35px;
color: white;
display: flex;
background-color: rgb(100, 100, 100,0.3);
border-radius: 4px;
font-size: 1.2em;
align-self: flex-end;
justify-content: space-evenly;
margin-bottom: 0.9em;
}
.date-range .days input
{
height: 35px;
outline: none;
border: none;
background-color:transparent;
color:white;
font-size: 1em;
width: 40px;
}
.date-range .days
{
background-color: rgb(255, 255, 255, 0.1);
padding-inline: 10px;
}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number] {
-moz-appearance: textfield;
}
.date-range .header,
.date-range .trailer
{
padding-inline: 10px;
align-self: center;
}
.stat-item-name a
{
text-decoration: none;
color: white;
}
.stat-item-name a:hover
{
color: rgb(0, 164, 219);
}

View File

@@ -1,135 +1,56 @@
.watch-stats
{
.card{
border: 0 !important;
max-width: 300px;
min-height: 790px;
}
.card-banner
{
flex-direction: row;
}
.stat-card-image {
max-width: 100%;
max-height: 420px;
height: 100%;
}
.stat-items
{
color: white;
}
.stat-item-index {
padding-right: 5px;
color: grey;
}
.stat-item-count {
/* width: 10%; */
text-align: right;
color: #00A4DC;
font-weight: 500;
font-size: 1.1em;
}
.Heading
{
display: flex;
margin-bottom: 10px;
margin-bottom: 20px;
}
.Heading h1
{
padding-right: 10px;
/* margin: 0; */
}
.stat-cards-container
{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(520px, 520px));
grid-auto-rows: 200px;/* max-width+offset so 215 + 20*/
margin-right: 20px;
margin-top: 4px;
}
.stats-card
{
width: 500px;
height: 180px;
display: flex;
color: white;
/* box-shadow: 0 0 20px 5px rgba(0, 0, 0, 0.5); */
background: linear-gradient(to right, #00A4DC, #AA5CC3);
background-size: cover;
border-radius: 4px;
}
.library-icons
{
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.stats-header {
display: flex;
justify-content: space-between;
color: white;
font-weight: 500;
}
.stats-header-plays {
color: lightgray;
font-weight: 300;
}
.stat-item {
display: flex;
justify-content: space-between;
width: 100%;
height: 20px;
margin-bottom: 5px;
}
.stat-item-index {
padding-top: 6px;
font-size: 0.8em;
padding-right: 2px;
color: grey;
text-align: right;
}
.stat-item-name {
width: 85%;
}
.stat-item-count {
width: 10%;
text-align: right;
color: #00A4DC;
font-weight: 500;
font-size: 1.1em;
}
.popular-image
{
height: 180px;
width: 175px;
background-color: rgb(0, 0, 0, 0.6);
border-radius:4px 0 0 4px;
}
.popular-banner-image
{
border-radius:4px 0 0 4px;
height: 180px;
width: 120px;
}
.popular-user-image-container
{
display: flex;
justify-content: center;
align-items: center;
}
.popular-user-image
{
border-radius: 50%;
width: 80%;
object-fit: cover;
}
.stats{
width: 100%;
padding: 5px 20px;
backdrop-filter: blur(4px);
border-radius: 0 4px 4px 0 ;
background-color: rgb(0, 0, 0, 0.6);
}
.date-range
{
width: 220px;
@@ -141,7 +62,7 @@
font-size: 1.2em;
align-self: flex-end;
justify-content: space-evenly;
margin-bottom: 0.9em;
}
@@ -178,16 +99,4 @@ input[type=number] {
{
padding-inline: 10px;
align-self: center;
}
.stat-item-name a
{
text-decoration: none;
color: white;
}
.stat-item-name a:hover
{
color: rgb(0, 164, 219);
}

View File

@@ -1,3 +1,8 @@
.watch-stats
{
margin-top: 10px;
}
.graph
{
@@ -32,6 +37,11 @@
flex: 1;
}
.main-widget h1
{
margin-bottom: 10px !important;
}
.statistics-widget
{
flex: 1;
@@ -39,6 +49,10 @@
/* margin-right: 20px; */
}
.statistics-widget h1{
margin-bottom: 10px !important;
}
.chart-canvas {
width: 100%;
height: 400px;

View File

@@ -3,6 +3,7 @@
color: white;
padding-right: 20px;
padding-bottom: 50px;
margin-top: 10px;
}
.user-activity-table {
@@ -87,6 +88,7 @@ td:first-child {
align-items: center;
justify-content: flex-end;
margin-top: 1rem;
color: white;
}
.page-btn {
@@ -126,7 +128,6 @@ td:first-child {
font-size: 1.2em;
align-self: flex-end;
justify-content: space-between;
margin-bottom: 0.9em;
}
.pagination-range select

View File

@@ -67,7 +67,7 @@ function Libraries() {
return (
<div className="libraries">
<h1>Libraries</h1>
<h1 className="py-4">Libraries</h1>
<div className="libraries-container">
{data &&
data.map((item) => (

View File

@@ -6,7 +6,8 @@ import './css/library/libraries.css';
import LibraryOverView from './components/libraryOverview';
// import LibraryOverView from './components/libraryOverview';
import HomeStatisticCards from './components/HomeStatisticCards';
@@ -16,40 +17,40 @@ function Testing() {
async function getToken(username,password) {
const response = await fetch('http://localhost:3003/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: username,
password: password,
}),
});
// async function getToken(username,password) {
// const response = await fetch('http://localhost:3003/login', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify({
// username: username,
// password: password,
// }),
// });
const data = await response.json();
return data.token;
}
// const data = await response.json();
// return data.token;
// }
// Make a GET request with JWT authentication
async function getDataWithAuth() {
try {
const token = await getToken('test','pass'); // a function to get the JWT token
// console.log(token);
localStorage.setItem('token', token);
} catch (error) {
console.error(error);
}
}
getDataWithAuth();
// // Make a GET request with JWT authentication
// async function getDataWithAuth() {
// try {
// const token = await getToken('test','pass'); // a function to get the JWT token
// // console.log(token);
// localStorage.setItem('token', token);
// } catch (error) {
// console.error(error);
// }
// }
// getDataWithAuth();
return (
<div className='Activity'>
<LibraryOverView/>
<HomeStatisticCards/>
</div>

View File

@@ -141,7 +141,7 @@ function Users() {
return (
<div className="Users">
<div className="Heading">
<h1>All Users</h1>
<h1 >All Users</h1>
<div className="pagination-range">
<div className="header">Items</div>
<select value={itemCount} onChange={(event) => {setItemCount(event.target.value); setCurrentPage(1);}}>