add frontend
This commit is contained in:
parent
36d97eb58c
commit
45b782e94c
0
frontend/__init__.py
Normal file
0
frontend/__init__.py
Normal file
3
frontend/admin.py
Normal file
3
frontend/admin.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
6
frontend/apps.py
Normal file
6
frontend/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class FrontendConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'frontend'
|
3
frontend/models.py
Normal file
3
frontend/models.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
37
frontend/static/css/index.css
Normal file
37
frontend/static/css/index.css
Normal file
@ -0,0 +1,37 @@
|
||||
body {
|
||||
--nav-width: 200px;
|
||||
margin: 0 0 0 var(--nav-width);
|
||||
font-family: 'Quicksand', sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: var(--nav-width);
|
||||
height: 100vh;
|
||||
background: #222222;
|
||||
}
|
||||
|
||||
.nav__link {
|
||||
display: block;
|
||||
padding: 12px 18px;
|
||||
text-decoration: none;
|
||||
color: #eeeeee;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.nav__link:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
#app {
|
||||
margin: 2em;
|
||||
line-height: 1.5;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #009579;
|
||||
}
|
63
frontend/static/js/index.js
Normal file
63
frontend/static/js/index.js
Normal file
@ -0,0 +1,63 @@
|
||||
import Dashboard from "./views/Dashboard.js";
|
||||
import Posts from "./views/Posts.js";
|
||||
import PostView from "./views/PostView.js";
|
||||
import Settings from "./views/Settings.js";
|
||||
|
||||
const pathToRegex = path => new RegExp("^" + path.replace(/\//g, "\\/").replace(/:\w+/g, "(.+)") + "$");
|
||||
|
||||
const getParams = match => {
|
||||
const values = match.result.slice(1);
|
||||
const keys = Array.from(match.route.path.matchAll(/:(\w+)/g)).map(result => result[1]);
|
||||
|
||||
return Object.fromEntries(keys.map((key, i) => {
|
||||
return [key, values[i]];
|
||||
}));
|
||||
};
|
||||
|
||||
const navigateTo = url => {
|
||||
history.pushState(null, null, url);
|
||||
router();
|
||||
};
|
||||
|
||||
const router = async () => {
|
||||
const routes = [
|
||||
{ path: "/", view: Dashboard },
|
||||
{ path: "/posts", view: Posts },
|
||||
{ path: "/posts/:id", view: PostView },
|
||||
{ path: "/settings", view: Settings }
|
||||
];
|
||||
|
||||
// Test each route for potential match
|
||||
const potentialMatches = routes.map(route => {
|
||||
return {
|
||||
route: route,
|
||||
result: location.pathname.match(pathToRegex(route.path))
|
||||
};
|
||||
});
|
||||
|
||||
let match = potentialMatches.find(potentialMatch => potentialMatch.result !== null);
|
||||
|
||||
if (!match) {
|
||||
match = {
|
||||
route: routes[0],
|
||||
result: [location.pathname]
|
||||
};
|
||||
}
|
||||
|
||||
const view = new match.route.view(getParams(match));
|
||||
|
||||
document.querySelector("#app").innerHTML = await view.getHtml();
|
||||
};
|
||||
|
||||
window.addEventListener("popstate", router);
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.body.addEventListener("click", e => {
|
||||
if (e.target.matches("[data-link]")) {
|
||||
e.preventDefault();
|
||||
navigateTo(e.target.href);
|
||||
}
|
||||
});
|
||||
|
||||
router();
|
||||
});
|
13
frontend/static/js/views/AbstractView.js
Normal file
13
frontend/static/js/views/AbstractView.js
Normal file
@ -0,0 +1,13 @@
|
||||
export default class {
|
||||
constructor(params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
setTitle(title) {
|
||||
document.title = title;
|
||||
}
|
||||
|
||||
async getHtml() {
|
||||
return "";
|
||||
}
|
||||
}
|
20
frontend/static/js/views/Dashboard.js
Normal file
20
frontend/static/js/views/Dashboard.js
Normal file
@ -0,0 +1,20 @@
|
||||
import AbstractView from "./AbstractView.js";
|
||||
|
||||
export default class extends AbstractView {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
this.setTitle("Dashboard");
|
||||
}
|
||||
|
||||
async getHtml() {
|
||||
return `
|
||||
<h1>Welcome back, Dom</h1>
|
||||
<p>
|
||||
Fugiat voluptate et nisi Lorem cillum anim sit do eiusmod occaecat irure do. Reprehenderit anim fugiat sint exercitation consequat. Sit anim laborum sit amet Lorem adipisicing ullamco duis. Anim in do magna ea pariatur et.
|
||||
</p>
|
||||
<p>
|
||||
<a href="/posts" data-link>View recent posts</a>.
|
||||
</p>
|
||||
`;
|
||||
}
|
||||
}
|
16
frontend/static/js/views/PostView.js
Normal file
16
frontend/static/js/views/PostView.js
Normal file
@ -0,0 +1,16 @@
|
||||
import AbstractView from "./AbstractView.js";
|
||||
|
||||
export default class extends AbstractView {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
this.postId = params.id;
|
||||
this.setTitle("Viewing Post");
|
||||
}
|
||||
|
||||
async getHtml() {
|
||||
return `
|
||||
<h1>Post</h1>
|
||||
<p>You are viewing post #${this.postId}.</p>
|
||||
`;
|
||||
}
|
||||
}
|
15
frontend/static/js/views/Posts.js
Normal file
15
frontend/static/js/views/Posts.js
Normal file
@ -0,0 +1,15 @@
|
||||
import AbstractView from "./AbstractView.js";
|
||||
|
||||
export default class extends AbstractView {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
this.setTitle("Posts");
|
||||
}
|
||||
|
||||
async getHtml() {
|
||||
return `
|
||||
<h1>Posts</h1>
|
||||
<p>You are viewing the posts!</p>
|
||||
`;
|
||||
}
|
||||
}
|
15
frontend/static/js/views/Settings.js
Normal file
15
frontend/static/js/views/Settings.js
Normal file
@ -0,0 +1,15 @@
|
||||
import AbstractView from "./AbstractView.js";
|
||||
|
||||
export default class extends AbstractView {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
this.setTitle("Settings");
|
||||
}
|
||||
|
||||
async getHtml() {
|
||||
return `
|
||||
<h1>Settings</h1>
|
||||
<p>Manage your privacy and configuration.</p>
|
||||
`;
|
||||
}
|
||||
}
|
19
frontend/templates/index.html
Normal file
19
frontend/templates/index.html
Normal file
@ -0,0 +1,19 @@
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Single Page App</title>
|
||||
<link rel="stylesheet" href="{% static 'css/index.css' %}">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="nav">
|
||||
<a href="/" class="nav__link" data-link>Dashboard</a>
|
||||
<a href="/posts" class="nav__link" data-link>Posts</a>
|
||||
<a href="/settings" class="nav__link" data-link>Settings</a>
|
||||
</nav>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="{% static 'js/index.js' %}"></script>
|
||||
</body>
|
||||
</html>
|
3
frontend/tests.py
Normal file
3
frontend/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
7
frontend/urls.py
Normal file
7
frontend/urls.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django.urls import path, re_path
|
||||
|
||||
from .views import index_view
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r'^', index_view ,name="index"),
|
||||
]
|
6
frontend/views.py
Normal file
6
frontend/views.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
|
||||
def index_view(req):
|
||||
return render(req, 'index.html');
|
@ -40,6 +40,7 @@ CORS_ORIGIN_WHITELIST = (
|
||||
INSTALLED_APPS = [
|
||||
'accounts.apps.AccountsConfig',
|
||||
'profiles.apps.ProfilesConfig',
|
||||
'frontend.apps.FrontendConfig',
|
||||
|
||||
'corsheaders',
|
||||
'rest_framework',
|
||||
|
@ -20,5 +20,6 @@ from django.urls import path, include
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('accounts/', include('accounts.urls')),
|
||||
path('test/', include('frontend.urls')),
|
||||
path('profiles/', include('profiles.urls')),
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user