From 45b782e94ccff61add60f6a1dcd49704f236bc75 Mon Sep 17 00:00:00 2001 From: AdrienLSH Date: Tue, 21 Nov 2023 19:15:16 +0100 Subject: [PATCH] add frontend --- frontend/__init__.py | 0 frontend/admin.py | 3 ++ frontend/apps.py | 6 +++ frontend/models.py | 3 ++ frontend/static/css/index.css | 37 ++++++++++++++ frontend/static/js/index.js | 63 ++++++++++++++++++++++++ frontend/static/js/views/AbstractView.js | 13 +++++ frontend/static/js/views/Dashboard.js | 20 ++++++++ frontend/static/js/views/PostView.js | 16 ++++++ frontend/static/js/views/Posts.js | 15 ++++++ frontend/static/js/views/Settings.js | 15 ++++++ frontend/templates/index.html | 19 +++++++ frontend/tests.py | 3 ++ frontend/urls.py | 7 +++ frontend/views.py | 6 +++ trancendence/settings.py | 1 + trancendence/urls.py | 1 + 17 files changed, 228 insertions(+) create mode 100644 frontend/__init__.py create mode 100644 frontend/admin.py create mode 100644 frontend/apps.py create mode 100644 frontend/models.py create mode 100644 frontend/static/css/index.css create mode 100644 frontend/static/js/index.js create mode 100644 frontend/static/js/views/AbstractView.js create mode 100644 frontend/static/js/views/Dashboard.js create mode 100644 frontend/static/js/views/PostView.js create mode 100644 frontend/static/js/views/Posts.js create mode 100644 frontend/static/js/views/Settings.js create mode 100644 frontend/templates/index.html create mode 100644 frontend/tests.py create mode 100644 frontend/urls.py create mode 100644 frontend/views.py diff --git a/frontend/__init__.py b/frontend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/frontend/admin.py b/frontend/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/frontend/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/frontend/apps.py b/frontend/apps.py new file mode 100644 index 0000000..04f7b89 --- /dev/null +++ b/frontend/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class FrontendConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'frontend' diff --git a/frontend/models.py b/frontend/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/frontend/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/frontend/static/css/index.css b/frontend/static/css/index.css new file mode 100644 index 0000000..9416823 --- /dev/null +++ b/frontend/static/css/index.css @@ -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; +} \ No newline at end of file diff --git a/frontend/static/js/index.js b/frontend/static/js/index.js new file mode 100644 index 0000000..f63c27c --- /dev/null +++ b/frontend/static/js/index.js @@ -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(); +}); \ No newline at end of file diff --git a/frontend/static/js/views/AbstractView.js b/frontend/static/js/views/AbstractView.js new file mode 100644 index 0000000..18bf83f --- /dev/null +++ b/frontend/static/js/views/AbstractView.js @@ -0,0 +1,13 @@ +export default class { + constructor(params) { + this.params = params; + } + + setTitle(title) { + document.title = title; + } + + async getHtml() { + return ""; + } +} \ No newline at end of file diff --git a/frontend/static/js/views/Dashboard.js b/frontend/static/js/views/Dashboard.js new file mode 100644 index 0000000..e2f4409 --- /dev/null +++ b/frontend/static/js/views/Dashboard.js @@ -0,0 +1,20 @@ +import AbstractView from "./AbstractView.js"; + +export default class extends AbstractView { + constructor(params) { + super(params); + this.setTitle("Dashboard"); + } + + async getHtml() { + return ` +

Welcome back, Dom

+

+ 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. +

+

+ View recent posts. +

+ `; + } +} \ No newline at end of file diff --git a/frontend/static/js/views/PostView.js b/frontend/static/js/views/PostView.js new file mode 100644 index 0000000..24e2785 --- /dev/null +++ b/frontend/static/js/views/PostView.js @@ -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 ` +

Post

+

You are viewing post #${this.postId}.

+ `; + } +} diff --git a/frontend/static/js/views/Posts.js b/frontend/static/js/views/Posts.js new file mode 100644 index 0000000..06ff6c9 --- /dev/null +++ b/frontend/static/js/views/Posts.js @@ -0,0 +1,15 @@ +import AbstractView from "./AbstractView.js"; + +export default class extends AbstractView { + constructor(params) { + super(params); + this.setTitle("Posts"); + } + + async getHtml() { + return ` +

Posts

+

You are viewing the posts!

+ `; + } +} \ No newline at end of file diff --git a/frontend/static/js/views/Settings.js b/frontend/static/js/views/Settings.js new file mode 100644 index 0000000..a54cf89 --- /dev/null +++ b/frontend/static/js/views/Settings.js @@ -0,0 +1,15 @@ +import AbstractView from "./AbstractView.js"; + +export default class extends AbstractView { + constructor(params) { + super(params); + this.setTitle("Settings"); + } + + async getHtml() { + return ` +

Settings

+

Manage your privacy and configuration.

+ `; + } +} \ No newline at end of file diff --git a/frontend/templates/index.html b/frontend/templates/index.html new file mode 100644 index 0000000..6fcaec3 --- /dev/null +++ b/frontend/templates/index.html @@ -0,0 +1,19 @@ +{% load static %} + + + + + + Single Page App + + + + +
+ + + diff --git a/frontend/tests.py b/frontend/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/frontend/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/frontend/urls.py b/frontend/urls.py new file mode 100644 index 0000000..da63192 --- /dev/null +++ b/frontend/urls.py @@ -0,0 +1,7 @@ +from django.urls import path, re_path + +from .views import index_view + +urlpatterns = [ + re_path(r'^', index_view ,name="index"), +] diff --git a/frontend/views.py b/frontend/views.py new file mode 100644 index 0000000..2d888d5 --- /dev/null +++ b/frontend/views.py @@ -0,0 +1,6 @@ +from django.shortcuts import render + +# Create your views here. + +def index_view(req): + return render(req, 'index.html'); diff --git a/trancendence/settings.py b/trancendence/settings.py index 6aa5548..a8d3760 100644 --- a/trancendence/settings.py +++ b/trancendence/settings.py @@ -40,6 +40,7 @@ CORS_ORIGIN_WHITELIST = ( INSTALLED_APPS = [ 'accounts.apps.AccountsConfig', 'profiles.apps.ProfilesConfig', + 'frontend.apps.FrontendConfig', 'corsheaders', 'rest_framework', diff --git a/trancendence/urls.py b/trancendence/urls.py index 235a3aa..bcf420d 100644 --- a/trancendence/urls.py +++ b/trancendence/urls.py @@ -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')), ]