Added documentation on how to run the backend and frontend code
This commit is contained in:
parent
1ef9bdce2b
commit
7a361e9fd0
11
Readme.md
11
Readme.md
@ -23,3 +23,14 @@ cd build/html
|
||||
python3 -m http.server
|
||||
```
|
||||
The website can be accessed at **localhost:8000**
|
||||
|
||||
## Development
|
||||
To run the backend server navigate to ``herreweb_backend/`` and run:
|
||||
|
||||
> python3 manage.py runserver
|
||||
|
||||
And for the frontend, navigate to ``herreweb_frontend`` and run:
|
||||
|
||||
> npm start
|
||||
|
||||
The file servers are accessible on ports 8000 and 3000.
|
||||
|
@ -1,11 +1,27 @@
|
||||
from django.db import models
|
||||
from herreweb_backend.utils import *
|
||||
|
||||
import os
|
||||
from uuid import uuid4
|
||||
|
||||
def path_and_rename(path):
|
||||
def wrapper(instance, filename):
|
||||
ext = filename.split('.')[-1]
|
||||
# get filename
|
||||
if instance.pk:
|
||||
filename = '{}.{}'.format(instance.pk, ext)
|
||||
else:
|
||||
# set filename as random string
|
||||
filename = '{}.{}'.format(uuid4().hex, ext)
|
||||
# return the whole path to the file
|
||||
return os.path.join(path, filename)
|
||||
return wrapper
|
||||
|
||||
class Project(models.Model):
|
||||
title = models.CharField(max_length=100)
|
||||
description = models.TextField(default="No description added")
|
||||
status = models.IntegerField(default=ProjectStatus.RUNNING)
|
||||
image = models.ImageField(upload_to="static/project_images/", null=True, blank=True)
|
||||
image = models.ImageField(upload_to=path_and_rename("static/project_images/"), null=True, blank=True)
|
||||
rtd_url = models.CharField(max_length=200, null=True, blank=True)
|
||||
url = models.CharField(max_length=200, null=True, blank=True)
|
||||
visible = models.BooleanField(default=False)
|
||||
|
BIN
herreweb_backend/static/project_images/1.png
Normal file
BIN
herreweb_backend/static/project_images/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 185 KiB |
Binary file not shown.
After Width: | Height: | Size: 185 KiB |
BIN
herreweb_backend/static/project_images/title/GHIDRA_1.png
Normal file
BIN
herreweb_backend/static/project_images/title/GHIDRA_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 185 KiB |
61
herreweb_frontend/package-lock.json
generated
61
herreweb_frontend/package-lock.json
generated
@ -13,6 +13,7 @@
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.6.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"web-vitals": "^2.1.4"
|
||||
@ -3089,6 +3090,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.2.1.tgz",
|
||||
"integrity": "sha512-XiY0IsyHR+DXYS5vBxpoBe/8veTeoRpMHP+vDosLZxL5bnpetzI0igkxkLZS235ldLzyfkxF+2divEwWHP3vMQ==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-babel": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||
@ -14187,6 +14196,36 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.6.1.tgz",
|
||||
"integrity": "sha512-YkvlYRusnI/IN0kDtosUCgxqHeulN5je+ew8W+iA1VvFhf86kA+JEI/X/8NqYcr11hCDDp906S+SGMpBheNeYQ==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.6.1.tgz",
|
||||
"integrity": "sha512-u+8BKUtelStKbZD5UcY0NY90WOzktrkJJhyhNg7L0APn9t1qJNLowzrM9CHdpB6+rcPt6qQrlkIXsTvhuXP68g==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.2.1",
|
||||
"react-router": "6.6.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-scripts": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||
@ -19110,6 +19149,11 @@
|
||||
"source-map": "^0.7.3"
|
||||
}
|
||||
},
|
||||
"@remix-run/router": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.2.1.tgz",
|
||||
"integrity": "sha512-XiY0IsyHR+DXYS5vBxpoBe/8veTeoRpMHP+vDosLZxL5bnpetzI0igkxkLZS235ldLzyfkxF+2divEwWHP3vMQ=="
|
||||
},
|
||||
"@rollup/plugin-babel": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||
@ -27028,6 +27072,23 @@
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
||||
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
|
||||
},
|
||||
"react-router": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.6.1.tgz",
|
||||
"integrity": "sha512-YkvlYRusnI/IN0kDtosUCgxqHeulN5je+ew8W+iA1VvFhf86kA+JEI/X/8NqYcr11hCDDp906S+SGMpBheNeYQ==",
|
||||
"requires": {
|
||||
"@remix-run/router": "1.2.1"
|
||||
}
|
||||
},
|
||||
"react-router-dom": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.6.1.tgz",
|
||||
"integrity": "sha512-u+8BKUtelStKbZD5UcY0NY90WOzktrkJJhyhNg7L0APn9t1qJNLowzrM9CHdpB6+rcPt6qQrlkIXsTvhuXP68g==",
|
||||
"requires": {
|
||||
"@remix-run/router": "1.2.1",
|
||||
"react-router": "6.6.1"
|
||||
}
|
||||
},
|
||||
"react-scripts": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||
|
@ -8,6 +8,7 @@
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.6.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"web-vitals": "^2.1.4"
|
||||
|
@ -2,12 +2,14 @@ import logo from '../static/logo.svg';
|
||||
import '../static/App.css';
|
||||
import Projects from './Projects';
|
||||
import AppHeader from './AppHeader';
|
||||
import AppFooter from './AppFooter';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="App">
|
||||
<AppHeader />
|
||||
<Projects />
|
||||
<AppFooter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
14
herreweb_frontend/src/components/AppFooter.js
Normal file
14
herreweb_frontend/src/components/AppFooter.js
Normal file
@ -0,0 +1,14 @@
|
||||
/* eslint-disable jsx-a11y/accessible-emoji */
|
||||
import React, { useState, useEffect } from "react";
|
||||
import "../static/AppFooter.css";
|
||||
|
||||
export default function AppFooter() {
|
||||
|
||||
return (
|
||||
<footer className="Footer">
|
||||
<div>
|
||||
Copyright @Herreweb
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import React, { Component } from "react"
|
||||
import '../static/Projects.css';
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const projectItems = [
|
||||
];
|
||||
@ -25,32 +26,32 @@ class Projects extends Component {
|
||||
return (
|
||||
<main className="content">
|
||||
<div className="projects-grid-container">
|
||||
{this.state.projectItems.map(item => (
|
||||
<div className="projects-grid-item">
|
||||
<h1>{item.title}</h1>
|
||||
<span>{item.description}</span>
|
||||
<span>{item.rtd_url}</span>
|
||||
{ this.state.projectItems.map(item => (
|
||||
<div className="project-grid-item">
|
||||
<h2>{item.title}</h2>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
{ item.url
|
||||
? <div className="project-url-btn">Website</div>
|
||||
: <div />
|
||||
}
|
||||
{ item.rtd_url
|
||||
? <div className="project-rtd-url-btn">Documentation</div>
|
||||
: <div />
|
||||
}
|
||||
<img className="project-image-box" src={item.image}/>
|
||||
<div className="description-box">{item.description}</div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</main>
|
||||
// <main className="content">
|
||||
// <div className="row">
|
||||
// <div className="col-md-6 col-sm-10 mx-auto p-0">
|
||||
// <div className="card p-3">
|
||||
// <ul className="list-group list-group-flush">
|
||||
// {this.state.projectItems.map(item => (
|
||||
// <div>
|
||||
// <h1>{item.title}</h1>
|
||||
// <span>{item.description}</span>
|
||||
// <span>{item.rtd_url}</span>
|
||||
// </div>
|
||||
// ))}
|
||||
// </ul>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// </main>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
|
14
herreweb_frontend/src/static/AppFooter.css
Normal file
14
herreweb_frontend/src/static/AppFooter.css
Normal file
@ -0,0 +1,14 @@
|
||||
.Footer {
|
||||
position: relative;
|
||||
bottom: 0; /* Stick it to the bottom */
|
||||
height: 70px;
|
||||
width: 100vw;
|
||||
|
||||
display: grid;
|
||||
grid-template-areas: "logo nav";
|
||||
|
||||
/* Cosmetics */
|
||||
background-color: #282c34;
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
@ -4,11 +4,85 @@
|
||||
gap: 1%;
|
||||
padding: 1%;
|
||||
margin-top: 70px;
|
||||
margin-left: 5%;
|
||||
margin-right: 5%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.projects-grid-item {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
margin: 1%;
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
.project-grid-item {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 2fr) repeat(5, 1fr);
|
||||
grid-template-rows: 1fr 2fr;
|
||||
grid-column-gap: 0px;
|
||||
grid-row-gap: 0px;
|
||||
align-items: center;
|
||||
background-color: rgb(241, 241, 241);
|
||||
border-radius:8px;
|
||||
padding: 1%;
|
||||
|
||||
}
|
||||
|
||||
.project-rtd-url-btn {
|
||||
margin: 2%;
|
||||
box-shadow:inset 0px 17px 10px -14px #29bbff;
|
||||
background:linear-gradient(to bottom, #2dabf9 5%, #0688fa 100%);
|
||||
background-color:#2dabf9;
|
||||
border-radius:8px;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
font-family:Arial;
|
||||
font-size:23px;
|
||||
font-weight:bold;
|
||||
padding:13px 32px;
|
||||
text-decoration:none;
|
||||
text-shadow:0px 1px 26px #263666;
|
||||
}
|
||||
|
||||
.project-rtd-url-btn:hover {
|
||||
background:linear-gradient(to bottom, #0688fa 5%, #2dabf9 100%);
|
||||
background-color:#0688fa;
|
||||
}
|
||||
|
||||
.project-rtd-url-btn:active {
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
|
||||
.project-url-btn {
|
||||
margin: 2%;
|
||||
box-shadow:inset 0px 17px 10px -14px #861400;
|
||||
background:linear-gradient(to bottom, #fb6363 5%, #cb0000 100%);
|
||||
background-color:#ff4b4b;
|
||||
border-radius:8px;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
font-family:Arial;
|
||||
font-size:23px;
|
||||
font-weight:bold;
|
||||
padding:13px 32px;
|
||||
text-decoration:none;
|
||||
text-shadow:0px 1px 26px #590700;
|
||||
}
|
||||
.project-url-btn:hover {
|
||||
background:linear-gradient(to bottom, #ff1616 5%, #ff0000 100%);
|
||||
background-color:#ff2626;
|
||||
}
|
||||
.project-url-btn:active {
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
|
||||
.project-image-box {
|
||||
width: 70%;
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
.description-box {
|
||||
padding: 5%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
@ -5,6 +5,7 @@ body {
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
code {
|
||||
|
Loading…
Reference in New Issue
Block a user