UI design
This commit is contained in:
parent
e37f48da37
commit
b0008014f6
|
@ -23,3 +23,21 @@ class Books(models.Model):
|
||||||
null=False,
|
null=False,
|
||||||
blank=False
|
blank=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
pages = models.TextField(
|
||||||
|
max_length=100,
|
||||||
|
null=False,
|
||||||
|
blank=False
|
||||||
|
)
|
||||||
|
|
||||||
|
readed = models.TextField(
|
||||||
|
max_length=100,
|
||||||
|
null=False,
|
||||||
|
blank=False
|
||||||
|
)
|
||||||
|
|
||||||
|
rating = models.TextField(
|
||||||
|
max_length=100,
|
||||||
|
null=False,
|
||||||
|
blank=False
|
||||||
|
)
|
|
@ -1,65 +1,65 @@
|
||||||
book;author;genre;pages;readed;rating
|
book;author;genre;pages;readed;rating
|
||||||
Omnia in Omnibus;Lisa Pennings;Sciencefiction;166;05-2013;4
|
Omnia in Omnibus;Lisa Pennings;Sciencefiction;166;2013-05-01;4
|
||||||
Het leven van Pi;Yann Martel;Roman;317;10-2020;4
|
Het leven van Pi;Yann Martel;Roman;317;2020-10-01;4
|
||||||
Ze komt nooit meer terug;Hans Koppel;Thriller;220;10-2020;5
|
Ze komt nooit meer terug;Hans Koppel;Thriller;220;2020-10-01;5
|
||||||
Vriendschapsverzoek;Laura Marshall;Thriller;368;10-2020;4
|
Vriendschapsverzoek;Laura Marshall;Thriller;368;2020-10-01;4
|
||||||
De analist;John Katzenbach;Thriller;518;11-2020;4
|
De analist;John Katzenbach;Thriller;518;2020-11-01;4
|
||||||
Komt een vrouw bij de hacker;Maria Genova;Thriller;224;11-2020;4
|
Komt een vrouw bij de hacker;Maria Genova;Thriller;224;2020-11-01;4
|
||||||
Niemand hoort het;Linwood Barclay;Thriller;304;11-2020;5
|
Niemand hoort het;Linwood Barclay;Thriller;304;2020-11-01;5
|
||||||
Lift;Linwood Barclay;Thriller;480;11-2020;3
|
Lift;Linwood Barclay;Thriller;480;2020-11-01;3
|
||||||
Kijk niet weg;Linwood Barclay;Thriller;400;12-2020;5
|
Kijk niet weg;Linwood Barclay;Thriller;400;2020-12-01;5
|
||||||
Het duistere net;Carmen Mola;Thriller;415;12-2020;5
|
Het duistere net;Carmen Mola;Thriller;415;2020-12-01;5
|
||||||
De 50/50-moorden;Steve Mosby;Thriller;344;12-2020;3
|
De 50/50-moorden;Steve Mosby;Thriller;344;2020-12-01;3
|
||||||
Zonder een woord;Linwood Barclay;Thriller;368;01-2021;5
|
Zonder een woord;Linwood Barclay;Thriller;368;2021-01-01;5
|
||||||
Geen veilige plek;Linwood Barclay;Thriller;368;01-2021;3
|
Geen veilige plek;Linwood Barclay;Thriller;368;2021-01-01;3
|
||||||
Op slot;Chris McGeorge;Thriller;320;01-2021;5
|
Op slot;Chris McGeorge;Thriller;320;2021-01-01;5
|
||||||
Alles is eventueel / 1408;Stephen King;Thriller;462;02-2021;3
|
Alles is eventueel / 1408;Stephen King;Thriller;462;2021-02-01;3
|
||||||
Waarom je niet zomaar moet stemmen waar je ouders op stemmen;Titia Hoogendoorn&Nienke Schuitemaker;Non-fictie;125;02-2021;4
|
Waarom je niet zomaar moet stemmen waar je ouders op stemmen;Titia Hoogendoorn&Nienke Schuitemaker;Non-fictie;125;2021-02-01;4
|
||||||
Geloof je ogen;Linwood Barclay;Thriller;384;02-2021;4
|
Geloof je ogen;Linwood Barclay;Thriller;384;2021-02-01;4
|
||||||
Voor ik ga slapen;SJ Watson;Thriller;333;03-2021;5
|
Voor ik ga slapen;SJ Watson;Thriller;333;2021-03-01;5
|
||||||
Echo;Tamara Geraeds;Thriller;280;03-2021;5
|
Echo;Tamara Geraeds;Thriller;280;2021-03-01;5
|
||||||
Niemand vertellen;Harlan Coben;Thriller;302;03-2021;4
|
Niemand vertellen;Harlan Coben;Thriller;302;2021-03-01;4
|
||||||
Ik zie je;Michael Berg;Thriller;320;04-2021;4
|
Ik zie je;Michael Berg;Thriller;320;2021-04-01;4
|
||||||
Toevluchtsoord;Jerome Loubry;Thriller;355;04-2021;5
|
Toevluchtsoord;Jerome Loubry;Thriller;355;2021-04-01;5
|
||||||
In een donker donker bos;Ruth Ware;Thriller;320;04-2021;3
|
In een donker donker bos;Ruth Ware;Thriller;320;2021-04-01;3
|
||||||
Een voor een;Ruth Ware;Thriller;368;04-2021;4
|
Een voor een;Ruth Ware;Thriller;368;2021-04-01;4
|
||||||
Vrees het ergste;Linwood Barclay;Thriller;400;05-2021;4
|
Vrees het ergste;Linwood Barclay;Thriller;400;2021-05-01;4
|
||||||
Het poppenhuis;W.R. Dantz;Thriller;270;05-2021;3
|
Het poppenhuis;W.R. Dantz;Thriller;270;2021-05-01;3
|
||||||
Malorie;Josh Malerman;Thriller;320;05-2021;4
|
Malorie;Josh Malerman;Thriller;320;2021-05-01;4
|
||||||
Opgejaagd;Gabriel Bergmoser;Thriller;256;06-2021;4
|
Opgejaagd;Gabriel Bergmoser;Thriller;256;2021-06-01;4
|
||||||
Reset;Blake Crouch;Thriller;352;06-2021;4
|
Reset;Blake Crouch;Thriller;352;2021-06-01;4
|
||||||
Wacht maar af;Loes den Hollander;Thriller;300;06-2021;4
|
Wacht maar af;Loes den Hollander;Thriller;300;2021-06-01;4
|
||||||
De Russische connectie;Gerrit Barendrecht;Thriller;320;06-2021;4
|
De Russische connectie;Gerrit Barendrecht;Thriller;320;2021-06-01;4
|
||||||
Wat jij niet ziet;M.J. Arlidge;Thriller;95;07-2021;3
|
Wat jij niet ziet;M.J. Arlidge;Thriller;95;2021-07-01;3
|
||||||
Het ongeluk;Linwood Barclay;Thriller;382;07-2021;4
|
Het ongeluk;Linwood Barclay;Thriller;382;2021-07-01;4
|
||||||
Slapen in een zee van sterren;Christopher Paolini;Sciencefiction;880;07-2021;2
|
Slapen in een zee van sterren;Christopher Paolini;Sciencefiction;880;2021-07-01;2
|
||||||
Tik Tak;Chris McGeorge;Thriller;320;07-2021;4
|
Tik Tak;Chris McGeorge;Thriller;320;2021-07-01;4
|
||||||
Gegijzeld;Clare Mackintosh;Thriller;397;08-2021;5
|
Gegijzeld;Clare Mackintosh;Thriller;397;2021-08-01;5
|
||||||
Eindbestemming;Marjolein van der Gaag&Marcella Kleine;Thriller;158;08-2021;4
|
Eindbestemming;Marjolein van der Gaag&Marcella Kleine;Thriller;158;2021-08-01;4
|
||||||
Een kille rilling;Bernard Minier;Thriller;582;09-2021;4
|
Een kille rilling;Bernard Minier;Thriller;582;2021-09-01;4
|
||||||
De nachtdienst;Esther Verhoef;Thriller;365;09-2021;5
|
De nachtdienst;Esther Verhoef;Thriller;365;2021-09-01;5
|
||||||
Kiekeboe;Chris McGeorge;Thriller;352;10-2021;3
|
Kiekeboe;Chris McGeorge;Thriller;352;2021-10-01;3
|
||||||
Noorderlicht;Mariska Overman;Thriller;313;10-2021;4
|
Noorderlicht;Mariska Overman;Thriller;313;2021-10-01;4
|
||||||
De kleine getuige;Jilliane Hoffman;Thriller;368;11-2021;4
|
De kleine getuige;Jilliane Hoffman;Thriller;368;2021-11-01;4
|
||||||
De marathon;Stephen King;Thriller;261;11-2021;4
|
De marathon;Stephen King;Thriller;261;2021-11-01;4
|
||||||
Het appartement;Tatiana de Rosnay;Roman;215;11-2021;4
|
Het appartement;Tatiana de Rosnay;Roman;215;2021-11-01;4
|
||||||
De intrigant;Patricia Snel;Thriller;189;12-2021;4
|
De intrigant;Patricia Snel;Thriller;189;2021-12-01;4
|
||||||
Een schuldig huis;Robert Goddard;Thriller;384;12-2021;5
|
Een schuldig huis;Robert Goddard;Thriller;384;2021-12-01;5
|
||||||
Te koop;Eva Monte;Thriller;350;12-2021;3
|
Te koop;Eva Monte;Thriller;350;2021-12-01;3
|
||||||
Prison Break S1B1;Paul T. Scheuring;Thriller;221;01-2022;5
|
Prison Break S1B1;Paul T. Scheuring;Thriller;221;2022-01-01;5
|
||||||
Prison Break S1B2;Ed van Eeden;Thriller;272;01-2022;4
|
Prison Break S1B2;Ed van Eeden;Thriller;272;2022-01-01;4
|
||||||
Prison Break S1B3;Paul T. Scheuring;Thriller;285;01-2022;4
|
Prison Break S1B3;Paul T. Scheuring;Thriller;285;2022-01-01;4
|
||||||
Herfstlied;Simone van der Vlugt;Thriller;277;02-2022;5
|
Herfstlied;Simone van der Vlugt;Thriller;277;2022-02-01;5
|
||||||
De gastenlijst;Lucy Foley;Thriller;352;02-2022;2
|
De gastenlijst;Lucy Foley;Thriller;352;2022-02-01;2
|
||||||
Anomalie;Herve le Tellier;Thriller;302;02-2022;2
|
Anomalie;Herve le Tellier;Thriller;302;2022-02-01;2
|
||||||
Prison Break S2B1;Paul T. Scheuring;Thriller;207;03-2022;4
|
Prison Break S2B1;Paul T. Scheuring;Thriller;207;2022-03-01;4
|
||||||
Prison Break S2B2;Paul T. Scheuring;Thriller;205;03-2022;4
|
Prison Break S2B2;Paul T. Scheuring;Thriller;205;2022-03-01;4
|
||||||
Prison Break S2B3;Paul T. Scheuring;Thriller;245;03-2022;4
|
Prison Break S2B3;Paul T. Scheuring;Thriller;245;2022-03-01;4
|
||||||
Ik weet je wachtwoord;Daniel Verlaan;Non-fictie;347;04-2022;5
|
Ik weet je wachtwoord;Daniel Verlaan;Non-fictie;347;2022-04-01;5
|
||||||
De vrouw die een jaar in bed ging liggen;Sue Townsend;Roman;368;04-2022;3
|
De vrouw die een jaar in bed ging liggen;Sue Townsend;Roman;368;2022-04-01;3
|
||||||
Moord in de bibliotheek;Agatha Christie;Thriller;256;04-2022;3
|
Moord in de bibliotheek;Agatha Christie;Thriller;256;2022-04-01;3
|
||||||
Geestdrift;Daniel Hecht;Thriller;509;05-2022;1
|
Geestdrift;Daniel Hecht;Thriller;509;2022-05-01;1
|
||||||
Moord in de Orient Expres;Agatha Christie;Thriller;222;05-2022;4
|
Moord in de Orient Expres;Agatha Christie;Thriller;222;2022-05-01;4
|
||||||
Crash;Jack Bowman;Thriller;344;05-2022;3
|
Crash;Jack Bowman;Thriller;344;2022-05-01;3
|
||||||
Erken mij;Esther Verhoef;Thriller;91;06-2022;4
|
Erken mij;Esther Verhoef;Thriller;91;2022-06-01;4
|
||||||
Gestrand;Sarah Goodwin;Thriller;352;06-2022;5
|
Gestrand;Sarah Goodwin;Thriller;352;2022-06-01;5
|
||||||
|
|
|
|
@ -3,5 +3,6 @@ from .views import *
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('books/genres', books_per_genre_per_month),
|
path('books/genres', books_per_genre_per_month),
|
||||||
|
path('books/genres/count', countGenres),
|
||||||
path('ratings', avg_ratings_per_month)
|
path('ratings', avg_ratings_per_month)
|
||||||
]
|
]
|
|
@ -1,13 +1,22 @@
|
||||||
|
from sqlite3 import connect
|
||||||
from rest_framework.decorators import api_view
|
from rest_framework.decorators import api_view
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from .models import Books
|
from .models import Books
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
import ras.settings
|
||||||
|
|
||||||
|
from sqlalchemy import create_engine
|
||||||
from .serializers import BooksSerializer
|
from .serializers import BooksSerializer
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
def getBooksData():
|
||||||
|
engine = create_engine('mysql+mysqldb://' + ras.settings.DATABASES['default']['USER'] + ':' + ras.settings.DATABASES['default']['PASSWORD'] + '@' + ras.settings.DATABASES['default']['HOST'] + ':3306/' + ras.settings.DATABASES['default']['NAME'])
|
||||||
|
df = pd.read_sql('SELECT * FROM api_books', engine, parse_dates={'readed': {'format': '%m-%Y'}})
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
def books_per_genre_per_month(request):
|
def books_per_genre_per_month(request):
|
||||||
|
|
||||||
|
@ -17,15 +26,17 @@ def books_per_genre_per_month(request):
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
# Get CSV file with book data
|
df = getBooksData()
|
||||||
df = pd.read_csv("api/static/books2.csv", encoding = "utf-8", header = 0, sep=';')
|
|
||||||
|
df['readed'] = pd.to_datetime(df['readed'], format='%Y-%m-%d')
|
||||||
|
df['readed'] = df['readed'].dt.strftime('%m-%Y')
|
||||||
|
|
||||||
# Filter data on year
|
# Filter data on year
|
||||||
df = df.where(df['readed'].str.contains(datayear))
|
df = df.where(df['readed'].str.contains(datayear))
|
||||||
|
|
||||||
# Filter array on genre and date
|
# Filter array on genre and date
|
||||||
booksPerMonth = df.groupby(['genre','readed'])['genre'].count().reset_index(name="count")
|
booksPerMonth = df.groupby(['genre','readed'])['genre'].count().reset_index(name="count")
|
||||||
booksPerMonth = booksPerMonth.sort_values(by='readed')
|
booksPerMonth = booksPerMonth.sort_values(by=['readed', 'count'], ascending=False)
|
||||||
|
|
||||||
for index, row in booksPerMonth.iterrows():
|
for index, row in booksPerMonth.iterrows():
|
||||||
data.append({
|
data.append({
|
||||||
|
@ -46,7 +57,10 @@ def avg_ratings_per_month(request):
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
# Get CSV file with book data
|
# Get CSV file with book data
|
||||||
df = pd.read_csv("api/static/books2.csv", encoding = "utf-8", header = 0, sep=';')
|
df = getBooksData()
|
||||||
|
|
||||||
|
df['readed'] = pd.to_datetime(df['readed'], format='%Y-%m-%d')
|
||||||
|
df['readed'] = df['readed'].dt.strftime('%m-%Y')
|
||||||
|
|
||||||
# Filter data on year
|
# Filter data on year
|
||||||
df = df.where(df['readed'].str.contains(datayear))
|
df = df.where(df['readed'].str.contains(datayear))
|
||||||
|
@ -63,3 +77,32 @@ def avg_ratings_per_month(request):
|
||||||
return Response(data)
|
return Response(data)
|
||||||
else:
|
else:
|
||||||
return Response("No year header included")
|
return Response("No year header included")
|
||||||
|
|
||||||
|
@api_view(['GET'])
|
||||||
|
def countGenres(request):
|
||||||
|
datayear = request.META.get('HTTP_YEAR')
|
||||||
|
|
||||||
|
if datayear:
|
||||||
|
data = []
|
||||||
|
|
||||||
|
# Get CSV file with book data
|
||||||
|
df = getBooksData()
|
||||||
|
|
||||||
|
df['readed'] = pd.to_datetime(df['readed'], format='%Y-%m-%d')
|
||||||
|
df['readed'] = df['readed'].dt.strftime('%m-%Y')
|
||||||
|
|
||||||
|
df = df.where(df['readed'].str.contains(datayear))
|
||||||
|
genres = df.groupby('genre')['genre'].count().reset_index(name="count")
|
||||||
|
genres = genres.sort_values(by='count', ascending=False)
|
||||||
|
|
||||||
|
for index, row in genres.iterrows():
|
||||||
|
|
||||||
|
data.append({
|
||||||
|
"genre": row['genre'],
|
||||||
|
"count": int(row['count'])
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response(data)
|
||||||
|
else:
|
||||||
|
return Response("No year header included")
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,56 @@ import React, { Component } from "react";
|
||||||
export default class App extends Component {
|
export default class App extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
year: new Date().getFullYear(),
|
||||||
|
}
|
||||||
|
|
||||||
|
this.yearsArray = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
changeYear(event) {
|
||||||
|
this.setState({
|
||||||
|
year: event.target.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
initDoughnut(data) {
|
||||||
|
|
||||||
|
var labels = [];
|
||||||
|
var counts = [];
|
||||||
|
|
||||||
|
data.forEach((count) => {
|
||||||
|
if (!labels.includes(count.genre)) {
|
||||||
|
labels.push(count.genre)
|
||||||
|
}
|
||||||
|
|
||||||
|
counts.push(count.count)
|
||||||
|
})
|
||||||
|
|
||||||
|
$("canvas#chartGenres").remove();
|
||||||
|
$("div.genresPercent").append('<canvas id="chartGenres"></canvas>');
|
||||||
|
|
||||||
|
var ctx = document.getElementById("chartGenres");
|
||||||
|
var myChart = new Chart(ctx, {
|
||||||
|
type: 'doughnut',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
label: '# of Tomatoes',
|
||||||
|
data: counts,
|
||||||
|
backgroundColor: [
|
||||||
|
'#696ffc', '#7596fa', '#92adfe', '#abc0ff'
|
||||||
|
],
|
||||||
|
borderWidth: 3,
|
||||||
|
borderColor: '#1f2940'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
//cutoutPercentage: 40,
|
||||||
|
responsive: true,
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initChart(data, ratings, year) {
|
initChart(data, ratings, year) {
|
||||||
|
@ -99,6 +149,9 @@ export default class App extends Component {
|
||||||
----------------------------------
|
----------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
$("canvas#chart").remove();
|
||||||
|
$("div.books-per-month").append('<canvas id="chart"></canvas>');
|
||||||
|
|
||||||
new Chart(document.getElementById('chart'), {
|
new Chart(document.getElementById('chart'), {
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
data: {
|
data: {
|
||||||
|
@ -142,9 +195,43 @@ export default class App extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
fetch('/api/books/genres', {
|
||||||
|
"method": "GET",
|
||||||
|
"headers": {
|
||||||
|
"year": this.state.year
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(books => {
|
||||||
|
fetch('/api/ratings', {
|
||||||
|
"method": "GET",
|
||||||
|
"headers": {
|
||||||
|
"year": this.state.year
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(ratings => {
|
||||||
|
this.initChart(books, ratings, this.state.year);
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
fetch('/api/books/genres/count', {
|
||||||
|
"method": "GET",
|
||||||
|
"headers": {
|
||||||
|
"year": this.state.year
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
this.initDoughnut(data);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
|
||||||
var currentyear = new Date("2021-09-29").getFullYear()
|
var currentyear = this.state.year ? this.state.year : new Date().getFullYear()
|
||||||
|
|
||||||
fetch('/api/books/genres', {
|
fetch('/api/books/genres', {
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
|
@ -162,19 +249,93 @@ export default class App extends Component {
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(ratings => {
|
.then(ratings => {
|
||||||
console.log(ratings);
|
|
||||||
this.initChart(books, ratings, currentyear);
|
this.initChart(books, ratings, currentyear);
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
fetch('/api/books/genres/count', {
|
||||||
|
"method": "GET",
|
||||||
|
"headers": {
|
||||||
|
"year": this.state.year
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
this.initDoughnut(data);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="books-per-month"><canvas id="chart"></canvas></div>
|
<div className="sidebar">
|
||||||
</React.Fragment>
|
<ul className="sidebar_menu">
|
||||||
|
<li className="menu-item">
|
||||||
|
<div className="menu-item-label">
|
||||||
|
<div className="menu-item-label-name"><i className="fa fa-chart-bar"></i> Dashboard</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div className="menu-item-label">
|
||||||
|
<div className="menu-item-label-name"><i class="fa fa-book-open"></i> Boeken</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className="content">
|
||||||
|
<div className="filter">
|
||||||
|
<div className="container-fluid">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-4">
|
||||||
|
<span style={{ color: '#ffffff', display: 'inline-block', width: 'auto' }}>Jaar: </span>
|
||||||
|
<select style={{ display: 'inline-block', width: 'auto' }} defaultValue={this.state.year} onChange={(event) => this.changeYear(event)}>
|
||||||
|
<option value="2020">2020</option>
|
||||||
|
<option value="2021">2021</option>
|
||||||
|
<option value="2022">2022</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-md-4"></div>
|
||||||
|
|
||||||
|
<div className="col-md-4"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="books-stats">
|
||||||
|
<div className="container-fluid">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-4">
|
||||||
|
<div className="stat-block">
|
||||||
|
<span>Boeken</span>
|
||||||
|
<span>17</span>
|
||||||
|
<span>-20%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-4">
|
||||||
|
<div className="stat-block">
|
||||||
|
<span>Bladzijdes</span>
|
||||||
|
<span>512</span>
|
||||||
|
<span>+5%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="container-fluid">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-8">
|
||||||
|
<div className="books-per-month"><canvas id="chart"></canvas></div>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-4">
|
||||||
|
<div className="genresPercent"><canvas id="chartGenres"></canvas></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because one or more lines are too long
|
@ -15,6 +15,10 @@
|
||||||
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
|
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
|
||||||
crossorigin=""/>
|
crossorigin=""/>
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT" crossorigin="anonymous">
|
||||||
|
|
||||||
|
<script src="https://kit.fontawesome.com/c4a0df9f18.js" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
<!-- Make sure you put this AFTER Leaflet's CSS -->
|
<!-- Make sure you put this AFTER Leaflet's CSS -->
|
||||||
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
|
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
|
||||||
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
|
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
|
||||||
|
@ -22,13 +26,76 @@
|
||||||
<style>
|
<style>
|
||||||
html, body{
|
html, body{
|
||||||
background:#141b2d;
|
background:#141b2d;
|
||||||
|
margin:0;
|
||||||
|
padding:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.books-per-month{
|
.filter{
|
||||||
|
width:100%;
|
||||||
|
background:#1f2940;
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.books-per-month, .genresPercent{
|
||||||
background: #1f2940;
|
background: #1f2940;
|
||||||
margin:50px;
|
|
||||||
padding:20px;
|
padding:20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar{
|
||||||
|
position: fixed;
|
||||||
|
background-color: #1f2940;
|
||||||
|
width: 255px;
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: 0 0 20px rgb(0 0 0 / 10%);
|
||||||
|
/* overflow-y: scroll; */
|
||||||
|
z-index: 999998;
|
||||||
|
transition: width .25s;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
padding-top: 56px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content{
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 255px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .menu-item-label-name {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 100;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .menu-item-label-name i{
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .sidebar_menu {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .sidebar_menu li {
|
||||||
|
list-style-type: none;
|
||||||
|
color: #555;
|
||||||
|
padding: 15px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .sidebar_menu li.submenu-item {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 100;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -37,6 +104,8 @@
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
<script src="{% static "js/main.js" %}"></script>
|
<script src="{% static "js/main.js" %}"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
Loading…
Reference in New Issue