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

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