add frontend

This commit is contained in:
AdrienLSH 2023-11-21 19:15:16 +01:00
parent 36d97eb58c
commit 45b782e94c
17 changed files with 228 additions and 0 deletions

0
frontend/__init__.py Normal file
View File

3
frontend/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
frontend/apps.py Normal file
View 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
View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View 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;
}

View 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();
});

View File

@ -0,0 +1,13 @@
export default class {
constructor(params) {
this.params = params;
}
setTitle(title) {
document.title = title;
}
async getHtml() {
return "";
}
}

View 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>
`;
}
}

View 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>
`;
}
}

View 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>
`;
}
}

View 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>
`;
}
}

View 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
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

7
frontend/urls.py Normal file
View 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
View File

@ -0,0 +1,6 @@
from django.shortcuts import render
# Create your views here.
def index_view(req):
return render(req, 'index.html');

View File

@ -40,6 +40,7 @@ CORS_ORIGIN_WHITELIST = (
INSTALLED_APPS = [ INSTALLED_APPS = [
'accounts.apps.AccountsConfig', 'accounts.apps.AccountsConfig',
'profiles.apps.ProfilesConfig', 'profiles.apps.ProfilesConfig',
'frontend.apps.FrontendConfig',
'corsheaders', 'corsheaders',
'rest_framework', 'rest_framework',

View File

@ -20,5 +20,6 @@ from django.urls import path, include
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('accounts/', include('accounts.urls')), path('accounts/', include('accounts.urls')),
path('test/', include('frontend.urls')),
path('profiles/', include('profiles.urls')), path('profiles/', include('profiles.urls')),
] ]