too many changes, i'm tired for describe all. But I try fix themes logic, okay?
This commit is contained in:
parent
3de0e95569
commit
a4c5b441f6
@ -1,7 +1,8 @@
|
|||||||
|
import { AuthenticationPage, AuthenticationRules } from "../pages/auth/auth";
|
||||||
import { NewsData, NewsFeed } from "../pages/feed/news";
|
import { NewsData, NewsFeed } from "../pages/feed/news";
|
||||||
import { NewsItem } from "../pages/feed/news-item";
|
import { NewsItem } from "../pages/feed/news-item";
|
||||||
|
|
||||||
type EndpointURL = "" | `http${'s' | ''}://${string}`;
|
type EndpointURL = "/api" | `http${'s' | ''}://${string}`;
|
||||||
|
|
||||||
interface ErrorDetails {
|
interface ErrorDetails {
|
||||||
code: string,
|
code: string,
|
||||||
@ -14,17 +15,27 @@ interface APIResponse<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let newsFeed : NewsFeed | null = null;
|
let newsFeed : NewsFeed | null = null;
|
||||||
|
let authPage : AuthenticationPage | null = null;
|
||||||
|
|
||||||
class ErrorAPI extends Error {}
|
class ErrorAPI extends Error {}
|
||||||
|
|
||||||
export class ControllerAPI {
|
export class ControllerAPI {
|
||||||
protected endpoint: EndpointURL;
|
protected endpoint: EndpointURL;
|
||||||
constructor(endpoint: EndpointURL = "") {
|
constructor(endpoint: EndpointURL = "/api") {
|
||||||
this.endpoint = endpoint;
|
this.endpoint = endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async request<T>(path: string, options: RequestInit = {}): Promise<T> {
|
protected async request<T>(path: string, options: RequestInit = {}): Promise<T> {
|
||||||
const url = new URL(path, this.endpoint || window.location.origin).href;
|
let url : string;
|
||||||
|
if (this.endpoint === "/api") {
|
||||||
|
url = new URL("/api", window.location.origin).href + path;
|
||||||
|
}
|
||||||
|
else if (/\/$/i.test(this.endpoint)) {
|
||||||
|
url = this.endpoint + path.slice(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
url = this.endpoint + path;
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetch(url, options);
|
const response = await fetch(url, options);
|
||||||
const result: APIResponse<T> = await response.json();
|
const result: APIResponse<T> = await response.json();
|
||||||
@ -50,21 +61,21 @@ export class ControllerAPI {
|
|||||||
async isAuthenticated(): Promise<boolean> {
|
async isAuthenticated(): Promise<boolean> {
|
||||||
if (!this.checkFirstAuth()) return false;
|
if (!this.checkFirstAuth()) return false;
|
||||||
|
|
||||||
const result = await this.request<boolean>('/api/isAuthenticated', {
|
const result = await this.request<boolean>('/isAuthenticated', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
credentials: 'include' // Include cookies for authentication
|
credentials: 'include' // Include cookies for authentication
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNews(returnElement: boolean = false) : Promise<NewsFeed | NewsData[]> {
|
async getNews(returnPage: boolean = false) : Promise<NewsFeed | NewsData[]> {
|
||||||
this.throwIfUnauthed();
|
this.throwIfUnauthed();
|
||||||
|
|
||||||
const result = await this.request<NewsData[]>('/api/news', {
|
const result = await this.request<NewsData[]>('/news', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
credentials: 'include' // Include cookies for authentication
|
credentials: 'include' // Include cookies for authentication
|
||||||
});
|
});
|
||||||
if (!returnElement)
|
if (!returnPage)
|
||||||
return result;
|
return result;
|
||||||
if (!newsFeed)
|
if (!newsFeed)
|
||||||
newsFeed = new NewsFeed(result.map(x => new NewsItem(
|
newsFeed = new NewsFeed(result.map(x => new NewsItem(
|
||||||
@ -76,4 +87,15 @@ export class ControllerAPI {
|
|||||||
)));
|
)));
|
||||||
return newsFeed;
|
return newsFeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAuthRules(returnPage: boolean = false) : Promise<AuthenticationRules | AuthenticationPage> {
|
||||||
|
const result = await this.request<AuthenticationRules>('/authenticationRules', {
|
||||||
|
method: 'GET',
|
||||||
|
credentials: 'include' // Include cookies for authentication
|
||||||
|
});
|
||||||
|
if (!returnPage) return result;
|
||||||
|
if (!authPage)
|
||||||
|
authPage = new AuthenticationPage(result);
|
||||||
|
return authPage;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -58,4 +58,11 @@
|
|||||||
|
|
||||||
.nav-item {
|
.nav-item {
|
||||||
cursor: pointer; padding: 12px 24px; font-size: 1.5em;
|
cursor: pointer; padding: 12px 24px; font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card {
|
||||||
|
margin-left: 30vw;
|
||||||
|
margin-right: 30vw;
|
||||||
|
margin-top: 30vh;
|
||||||
|
margin-bottom: 30vh;
|
||||||
}
|
}
|
||||||
@ -1,12 +1,15 @@
|
|||||||
import { GefestEngine } from "./modules/Gefest/engine";
|
import { GefestEngine } from "./modules/Gefest/engine";
|
||||||
import { Navbar } from "./pages/navbar";
|
import { Navbar, themeToggle } from "./pages/navbar";
|
||||||
import { DarkStyle, LightStyle, defaultStyle } from "./styles";
|
import { DarkStyle, LightStyle, SupportedStyles } from "./styles";
|
||||||
import { ControllerAPI } from "./api/RESTful";
|
import { ControllerAPI } from "./api/RESTful";
|
||||||
import { NewsFeed } from "./pages/feed/news";
|
import { NewsFeed } from "./pages/feed/news";
|
||||||
import { AuthenticationPage } from "./pages/auth/auth";
|
import { AuthenticationPage } from "./pages/auth/auth";
|
||||||
|
|
||||||
// I'll add a dark mode toggle later, but for now let's just use the light style by default
|
// I'll add a dark mode toggle later, but for now let's just use the light style by default
|
||||||
let currentStyle = defaultStyle;
|
const defaultStyle = new LightStyle();
|
||||||
|
const styleMemLink = {
|
||||||
|
currentStyle: () : SupportedStyles => defaultStyle
|
||||||
|
};
|
||||||
|
|
||||||
{ // I hate trash in global scope, so I wrap it in a block
|
{ // I hate trash in global scope, so I wrap it in a block
|
||||||
const appElement = document.getElementById("app");
|
const appElement = document.getElementById("app");
|
||||||
@ -20,7 +23,7 @@ const api : ControllerAPI = new ControllerAPI();
|
|||||||
async function authInit() {
|
async function authInit() {
|
||||||
console.log("User is authenticated");
|
console.log("User is authenticated");
|
||||||
const newsFeed = await api.getNews(true) as NewsFeed;
|
const newsFeed = await api.getNews(true) as NewsFeed;
|
||||||
newsFeed.style = currentStyle;
|
newsFeed.style = styleMemLink.currentStyle;
|
||||||
const appElement = document.getElementById("app");
|
const appElement = document.getElementById("app");
|
||||||
if (appElement)
|
if (appElement)
|
||||||
appElement.innerHTML = newsFeed.build();
|
appElement.innerHTML = newsFeed.build();
|
||||||
@ -28,17 +31,35 @@ async function authInit() {
|
|||||||
|
|
||||||
async function logInInit () {
|
async function logInInit () {
|
||||||
console.log("User is not authenticated");
|
console.log("User is not authenticated");
|
||||||
const authPage = new AuthenticationPage();
|
const authPage = await api.getAuthRules(true) as AuthenticationPage;
|
||||||
authPage.style = currentStyle;
|
authPage.style = styleMemLink.currentStyle;
|
||||||
const appElement = document.getElementById("app");
|
const appElement = document.getElementById("app");
|
||||||
if (appElement)
|
if (appElement)
|
||||||
appElement.innerHTML = authPage.build();
|
appElement.innerHTML = authPage.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function changeStyleLogic () {
|
||||||
|
const themes : SupportedStyles[] = [
|
||||||
|
defaultStyle,
|
||||||
|
new DarkStyle()
|
||||||
|
];
|
||||||
|
let choosed = 0;
|
||||||
|
|
||||||
|
themeToggle.onClick = () => {
|
||||||
|
choosed++;
|
||||||
|
if (choosed >= themes.length)
|
||||||
|
choosed = 0;
|
||||||
|
|
||||||
|
styleMemLink.currentStyle = () => themes[choosed] as SupportedStyles;
|
||||||
|
GefestEngine.render();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
await changeStyleLogic();
|
||||||
// init navbar
|
// init navbar
|
||||||
const navbar = new Navbar();
|
const navbar = new Navbar();
|
||||||
navbar.style = currentStyle;
|
navbar.style = styleMemLink.currentStyle;
|
||||||
document.body.innerHTML = "<div id='app'></div>" + navbar.build();
|
document.body.innerHTML = "<div id='app'></div>" + navbar.build();
|
||||||
|
|
||||||
if (await api.isAuthenticated()) {
|
if (await api.isAuthenticated()) {
|
||||||
|
|||||||
@ -4,8 +4,9 @@ import { GefestStyle } from './style';
|
|||||||
// The general class of Gefest
|
// The general class of Gefest
|
||||||
type GefestElementEvents = "onClick";
|
type GefestElementEvents = "onClick";
|
||||||
export abstract class GefestElement {
|
export abstract class GefestElement {
|
||||||
style: GefestStyle | null = null;
|
style: GefestStyle | (() => GefestStyle) | null = null;
|
||||||
isHidden: boolean = false;
|
isHidden: boolean = false;
|
||||||
|
id : string | null = null;
|
||||||
//onClick: (() => void) | null = null;
|
//onClick: (() => void) | null = null;
|
||||||
readonly gefestId: string;
|
readonly gefestId: string;
|
||||||
protected content: (GefestElement | string)[] | string;
|
protected content: (GefestElement | string)[] | string;
|
||||||
@ -64,6 +65,8 @@ export abstract class GefestElement {
|
|||||||
* @returns The created GefestElement.
|
* @returns The created GefestElement.
|
||||||
*/
|
*/
|
||||||
static fromHTML(html: string): GefestElement {
|
static fromHTML(html: string): GefestElement {
|
||||||
|
console.warn("Legacy and experiemental function!");
|
||||||
|
|
||||||
const htmlElement = new DOMParser().parseFromString(html, 'text/html').body.firstChild as HTMLElement;
|
const htmlElement = new DOMParser().parseFromString(html, 'text/html').body.firstChild as HTMLElement;
|
||||||
const element = new (class extends GefestElement {
|
const element = new (class extends GefestElement {
|
||||||
protected wrapHTML(content: string): string {
|
protected wrapHTML(content: string): string {
|
||||||
@ -98,7 +101,7 @@ export abstract class GefestElement {
|
|||||||
* Call to GefestEngine for rerender element
|
* Call to GefestEngine for rerender element
|
||||||
*/
|
*/
|
||||||
update (): void {
|
update (): void {
|
||||||
GefestEngine.reRenderByGI(this.gefestId);
|
GefestEngine.render(this.gefestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,6 +115,11 @@ export abstract class GefestElement {
|
|||||||
else
|
else
|
||||||
this.removeAttribute('hidden');
|
this.removeAttribute('hidden');
|
||||||
|
|
||||||
|
if (this.id !== null)
|
||||||
|
this.setAttribute('id', this.id);
|
||||||
|
else
|
||||||
|
this.removeAttribute('id');
|
||||||
|
|
||||||
if (!isFromStyle)
|
if (!isFromStyle)
|
||||||
return this.applyStyle(this.render(), this);
|
return this.applyStyle(this.render(), this);
|
||||||
return this.render();
|
return this.render();
|
||||||
@ -200,8 +208,11 @@ export abstract class GefestElement {
|
|||||||
* @returns The styled HTML.
|
* @returns The styled HTML.
|
||||||
*/
|
*/
|
||||||
protected applyStyle(html: string, element?: GefestElement): string {
|
protected applyStyle(html: string, element?: GefestElement): string {
|
||||||
if (this.style)
|
if (this.style) {
|
||||||
|
if (typeof this.style === "function")
|
||||||
|
return this.style().applyStyle(html, element);
|
||||||
return this.style.applyStyle(html, element);
|
return this.style.applyStyle(html, element);
|
||||||
|
}
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,8 +233,9 @@ export abstract class GefestElement {
|
|||||||
*/
|
*/
|
||||||
protected wrapHTML (content: string): string {
|
protected wrapHTML (content: string): string {
|
||||||
const attrString = this.attributesToString();
|
const attrString = this.attributesToString();
|
||||||
return `<div ${attrString}>${content}</div>`;
|
return `<${this.htmlTag} ${attrString}>${content}</${this.htmlTag}>`;
|
||||||
}
|
}
|
||||||
|
protected htmlTag: string = "div";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the element and returns it as a string.
|
* Renders the element and returns it as a string.
|
||||||
@ -234,17 +246,23 @@ export abstract class GefestElement {
|
|||||||
return this.wrapHTML(this.content);
|
return this.wrapHTML(this.content);
|
||||||
}
|
}
|
||||||
const rendered : string[] = [];
|
const rendered : string[] = [];
|
||||||
for (const item of this.content) {
|
if (!this.isHidden)
|
||||||
if (typeof item === 'string') {
|
for (const item of this.content) {
|
||||||
rendered.push(item);
|
if (typeof item === 'string') {
|
||||||
}
|
rendered.push(item);
|
||||||
else if (item instanceof GefestElement) {
|
}
|
||||||
if (!item.style && this.style) {
|
else if (item instanceof GefestElement) {
|
||||||
item.style = this.style;
|
if (!item.style && this.style !== null) {
|
||||||
|
if (typeof this.style === "function") {
|
||||||
|
item.style = this.style;
|
||||||
|
}
|
||||||
|
else if (this.style instanceof GefestStyle) {
|
||||||
|
item.style = () => (this.style as GefestStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rendered.push(item.build());
|
||||||
}
|
}
|
||||||
rendered.push(item.build());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return this.wrapHTML(rendered.join(''));
|
return this.wrapHTML(rendered.join(''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,7 +2,7 @@ import { GefestElement } from "./element";
|
|||||||
|
|
||||||
// For protecting the set of elements from direct access
|
// For protecting the set of elements from direct access
|
||||||
const elements: Set<GefestElement> = new Set();
|
const elements: Set<GefestElement> = new Set();
|
||||||
const elementsMapping: Map<string, GefestElement> = new Map<string, GefestElement> ();
|
const elementsMapping: Record<string, GefestElement> = {};
|
||||||
export class GefestEngine {
|
export class GefestEngine {
|
||||||
static register (element: GefestElement) : string {
|
static register (element: GefestElement) : string {
|
||||||
elements.add(element);
|
elements.add(element);
|
||||||
@ -10,8 +10,8 @@ export class GefestEngine {
|
|||||||
let gefestId : string;
|
let gefestId : string;
|
||||||
do {
|
do {
|
||||||
gefestId = `gefest-${Math.random().toString(36).substr(2, 9)}`;
|
gefestId = `gefest-${Math.random().toString(36).substr(2, 9)}`;
|
||||||
} while(!!elementsMapping.get(gefestId));
|
} while(!!elementsMapping[gefestId]);
|
||||||
elementsMapping.set(gefestId, element);
|
elementsMapping[gefestId] = element;
|
||||||
|
|
||||||
return gefestId;
|
return gefestId;
|
||||||
}
|
}
|
||||||
@ -31,14 +31,28 @@ export class GefestEngine {
|
|||||||
await GefestEngine.activateOnClick();
|
await GefestEngine.activateOnClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
static reRenderByGI (gefestId: string) {
|
static render (gefestId: string | string[] | null = null) {
|
||||||
const gefestElement = elementsMapping.get(gefestId);
|
let gefestElements : string[] | null = null;
|
||||||
if (!gefestElement) return;
|
if (typeof gefestId === "string")
|
||||||
const elementHTML = document.querySelectorAll(`[data-gefest-id="${gefestId}"]`);
|
gefestId = [gefestId];
|
||||||
|
else if (gefestId === null) {
|
||||||
|
gefestId = Object.keys(elementsMapping);
|
||||||
|
gefestElements = gefestId;
|
||||||
|
}
|
||||||
|
//const gefestElement = elementsMapping.get(gefestId);
|
||||||
|
if (!gefestElements)
|
||||||
|
gefestElements = gefestId.filter(gid => !!elementsMapping[gid]);
|
||||||
|
if (gefestElements.length === 0) return;
|
||||||
|
const elementHTML = document.querySelectorAll('[data-gefest-id]');
|
||||||
|
|
||||||
if (elementHTML.length > 0) {
|
if (elementHTML.length > 0) {
|
||||||
const htmlElement = elementHTML[0] as HTMLElement;
|
for (let htmlElement of elementHTML) {
|
||||||
htmlElement.outerHTML = gefestElement.build();
|
const gid = htmlElement.getAttribute("data-gefest-id");
|
||||||
|
if (!gid || !elementsMapping[gid])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
htmlElement.outerHTML = elementsMapping[gid].build();
|
||||||
|
}
|
||||||
GefestEngine.activateOnClick();
|
GefestEngine.activateOnClick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,134 @@
|
|||||||
|
import { GefestElement } from "../../modules/Gefest/element";
|
||||||
|
import { GefestA } from "../../modules/Gefest/primitives/a";
|
||||||
|
import { GefestCenter } from "../../modules/Gefest/primitives/center";
|
||||||
|
import { GefestHeader } from "../../modules/Gefest/primitives/header";
|
||||||
import { DefaultElement } from "../default-element";
|
import { DefaultElement } from "../default-element";
|
||||||
|
|
||||||
export class AuthenticationPage extends DefaultElement {
|
export interface AuthenticationRules {
|
||||||
|
type: "password"
|
||||||
|
};
|
||||||
|
|
||||||
|
type formType = "text" | "email" | "password" | "textarea";
|
||||||
|
function getFormItem (elementHtmlId: string, title: string, type: formType = "text", placeholder : string | null = null): DefaultElement {
|
||||||
|
const label: DefaultElement = new (class extends DefaultElement {
|
||||||
|
constructor() {
|
||||||
|
super([
|
||||||
|
title
|
||||||
|
]);
|
||||||
|
this.addClass("form-label");
|
||||||
|
this.setAttribute("for", elementHtmlId);
|
||||||
|
}
|
||||||
|
protected htmlTag = "label";
|
||||||
|
});
|
||||||
|
const input: DefaultElement = new (class extends DefaultElement {
|
||||||
|
constructor() {
|
||||||
|
super([]);
|
||||||
|
this.id = elementHtmlId;
|
||||||
|
this.addClass("form-control");
|
||||||
|
if (!{
|
||||||
|
text: true,
|
||||||
|
email: true,
|
||||||
|
password: true,
|
||||||
|
textarea: false
|
||||||
|
}[type]) {
|
||||||
|
this.setAttribute("type", type);
|
||||||
|
}
|
||||||
|
if (placeholder !== null) {
|
||||||
|
this.setAttribute("placeholder", placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected htmlTag = {
|
||||||
|
text: "input",
|
||||||
|
email: "input",
|
||||||
|
password: "input",
|
||||||
|
textarea: "textarea"
|
||||||
|
}[type];
|
||||||
|
});
|
||||||
|
|
||||||
|
return new (class extends DefaultElement { constructor() { super([
|
||||||
|
label, input
|
||||||
|
]); this.addClass("mb-3"); } });
|
||||||
|
}
|
||||||
|
class RegisterForm extends DefaultElement {
|
||||||
|
link: GefestA;
|
||||||
|
constructor(authRules : AuthenticationRules) {
|
||||||
|
const header = new GefestHeader("Registration", 2);
|
||||||
|
header.addClass("card-title");
|
||||||
|
const link = new GefestA("Login to account");
|
||||||
|
link.addClass("link-secondary");
|
||||||
|
link.addClass("noselect");
|
||||||
|
link.setPersonalStyle("cursor: pointer;");
|
||||||
|
|
||||||
|
const args = [
|
||||||
|
getFormItem("username", "Username"),
|
||||||
|
getFormItem("password", "Password", "password"),
|
||||||
|
];
|
||||||
|
switch (authRules.type) {
|
||||||
|
case "password":
|
||||||
|
args.push(getFormItem(
|
||||||
|
"serverPassword",
|
||||||
|
"Server Password",
|
||||||
|
"password"
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
super([
|
||||||
|
new GefestCenter([header, link]),
|
||||||
|
...args
|
||||||
|
]);
|
||||||
|
this.link = link;
|
||||||
|
this.isHidden = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class LoginForm extends DefaultElement {
|
||||||
|
link: GefestA;
|
||||||
constructor() {
|
constructor() {
|
||||||
super([]);
|
const header = new GefestHeader("Login", 2);
|
||||||
|
header.addClass("card-title");
|
||||||
|
const link = new GefestA("Create a new account");
|
||||||
|
link.addClass("link-secondary");
|
||||||
|
link.addClass("noselect");
|
||||||
|
link.setPersonalStyle("cursor: pointer;");
|
||||||
|
|
||||||
|
super([
|
||||||
|
new GefestCenter([
|
||||||
|
header, link
|
||||||
|
]),
|
||||||
|
getFormItem("username", "Username"),
|
||||||
|
getFormItem("password", "Password", "password"),
|
||||||
|
]);
|
||||||
|
this.link = link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class AuthenticationPage extends DefaultElement {
|
||||||
|
constructor(authRules : AuthenticationRules) {
|
||||||
|
const login = new LoginForm;
|
||||||
|
const register = new RegisterForm(authRules);
|
||||||
|
|
||||||
|
const update = () => {
|
||||||
|
login.update();
|
||||||
|
register.update();
|
||||||
|
};
|
||||||
|
login.link.onClick = () => {
|
||||||
|
login.isHidden = true;
|
||||||
|
register.isHidden = false;
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
register.link.onClick = () => {
|
||||||
|
login.isHidden = false;
|
||||||
|
register.isHidden = true;
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
|
||||||
|
super([
|
||||||
|
new (class extends DefaultElement { constructor() { super([
|
||||||
|
login,
|
||||||
|
register
|
||||||
|
]); this.addClass("card-body"); } })
|
||||||
|
]);
|
||||||
|
this.addClass("card");
|
||||||
|
this.addClass("border");
|
||||||
|
this.addClass("auth-card");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,7 +2,7 @@ import { GefestElement } from "../modules/Gefest/element";
|
|||||||
import { SupportedStyles } from "../styles";
|
import { SupportedStyles } from "../styles";
|
||||||
|
|
||||||
export abstract class DefaultElement extends GefestElement {
|
export abstract class DefaultElement extends GefestElement {
|
||||||
style: SupportedStyles | null = null;
|
style: SupportedStyles | (() => SupportedStyles) | null = null;
|
||||||
constructor(content: (GefestElement | string)[] | string) {
|
constructor(content: (GefestElement | string)[] | string) {
|
||||||
super(content);
|
super(content);
|
||||||
}
|
}
|
||||||
@ -11,4 +11,14 @@ export abstract class DefaultElement extends GefestElement {
|
|||||||
if (!this.style) throw new Error("Setup style is required");
|
if (!this.style) throw new Error("Setup style is required");
|
||||||
return super.build(isFromStyle);
|
return super.build(isFromStyle);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DefaultRoundedButton extends DefaultElement {
|
||||||
|
constructor(btnContent : GefestElement | string) {
|
||||||
|
super([ btnContent ]);
|
||||||
|
this.setAttribute("type", "button");
|
||||||
|
this.addClass("btn");
|
||||||
|
this.addClass("rounded-circle");
|
||||||
|
this.addClass("border");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -28,7 +28,7 @@ class NewsUserInterfaceCard extends DefaultElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ^^ Card
|
// ^^ Card
|
||||||
class NewsUserInterfaceButton extends DefaultElement {
|
class NewsUserInterfaceButton extends DefaultElement { // <-- TODO: Fix it to DefaultRoundedButton
|
||||||
constructor(userType : UserType, card : NewsUserInterfaceCard) {
|
constructor(userType : UserType, card : NewsUserInterfaceCard) {
|
||||||
const uiIcon = new GefestI("");
|
const uiIcon = new GefestI("");
|
||||||
uiIcon.addClass({
|
uiIcon.addClass({
|
||||||
|
|||||||
@ -25,6 +25,7 @@ class NavbarButton extends DefaultElement {
|
|||||||
return `<li ${attrString}>${content}</li>`;
|
return `<li ${attrString}>${content}</li>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export const themeToggle = new NavbarButton("fas fa-paint-roller");
|
||||||
|
|
||||||
class NavbarItemContainerUL extends DefaultElement {
|
class NavbarItemContainerUL extends DefaultElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -37,7 +38,9 @@ class NavbarItemContainerUL extends DefaultElement {
|
|||||||
|
|
||||||
super([
|
super([
|
||||||
newsButton,
|
newsButton,
|
||||||
chatButton
|
chatButton,
|
||||||
|
|
||||||
|
themeToggle
|
||||||
]);
|
]);
|
||||||
this.addClass("navbar-nav");
|
this.addClass("navbar-nav");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { GefestElement } from "./modules/Gefest/element";
|
|||||||
import { Navbar } from "./pages/navbar";
|
import { Navbar } from "./pages/navbar";
|
||||||
import { isNewsUI, NewsUserInterface } from "./pages/feed/news";
|
import { isNewsUI, NewsUserInterface } from "./pages/feed/news";
|
||||||
|
|
||||||
export abstract class SkeletonStyle extends GefestStyle {
|
abstract class SkeletonStyle extends GefestStyle {
|
||||||
protected abstract navbar(element: GefestElement): void;
|
protected abstract navbar(element: GefestElement): void;
|
||||||
protected abstract newsui(element: GefestElement): void;
|
protected abstract newsui(element: GefestElement): void;
|
||||||
protected abstract styleHandle(element: GefestElement): void;
|
protected abstract styleHandle(element: GefestElement): void;
|
||||||
@ -64,6 +64,4 @@ export class LightStyle extends SkeletonStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SupportedStyles = SkeletonStyle;
|
export type SupportedStyles = SkeletonStyle;
|
||||||
|
|
||||||
export const defaultStyle = new LightStyle();
|
|
||||||
@ -1,10 +1,16 @@
|
|||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import { ApiResponse } from '../utils/rest-api-answer';
|
import { ApiResponse } from '../utils/rest-api-answer';
|
||||||
import { NewsItem, getTestNews } from "../utils/news";
|
import { getTestNews } from "../utils/news";
|
||||||
import authRequired from "../utils/auth-required";
|
import authRequired from "../utils/auth-required";
|
||||||
|
import { NewsItem } from "./models/news";
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
|
router.get('/authenticationRules', (req, res) => {
|
||||||
|
const response = new ApiResponse(req.authenticationRules);
|
||||||
|
return res.json(response.getAnswer());
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/isAuthenticated', (req, res) => {
|
router.get('/isAuthenticated', (req, res) => {
|
||||||
const response = new ApiResponse(req.isAuthenticated);
|
const response = new ApiResponse(req.isAuthenticated);
|
||||||
return res.json(response.getAnswer());
|
return res.json(response.getAnswer());
|
||||||
|
|||||||
3
src/api/models/AuthenticationRules.ts
Normal file
3
src/api/models/AuthenticationRules.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export interface AuthenticationRulesTypes {
|
||||||
|
type: "password";
|
||||||
|
}
|
||||||
14
src/api/models/news.ts
Normal file
14
src/api/models/news.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
export interface Source {
|
||||||
|
name: string,
|
||||||
|
icon?: string,
|
||||||
|
sourceURL?: string,
|
||||||
|
itemURL?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NewsItem {
|
||||||
|
id : number;
|
||||||
|
title : string;
|
||||||
|
content : string;
|
||||||
|
source: Source;
|
||||||
|
publishedAt : Date;
|
||||||
|
}
|
||||||
@ -1,19 +1,22 @@
|
|||||||
import express, { Request, Response } from 'express';
|
import express, { Request, Response } from 'express';
|
||||||
import api from './api';
|
import api from './api';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { AuthenticationRulesTypes } from './api/models/AuthenticationRules';
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = 3000;
|
const port = 3000;
|
||||||
|
|
||||||
declare module 'express-serve-static-core' {
|
declare module 'express-serve-static-core' {
|
||||||
interface Request {
|
interface Request {
|
||||||
isAuthenticated?: boolean;
|
isAuthenticated: boolean;
|
||||||
|
authenticationRules: AuthenticationRulesTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checking auth
|
// Checking auth
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
req.isAuthenticated = true; // Mock authentication, replace with real logic
|
req.authenticationRules = { type: "password" };
|
||||||
|
req.isAuthenticated = false; // Mock authentication, replace with real logic
|
||||||
// Add your authentication logic here
|
// Add your authentication logic here
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,17 +1,4 @@
|
|||||||
export interface Source {
|
import { NewsItem } from "../api/models/news";
|
||||||
name: string,
|
|
||||||
icon?: string,
|
|
||||||
sourceURL?: string,
|
|
||||||
itemURL?: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NewsItem {
|
|
||||||
id : number;
|
|
||||||
title : string;
|
|
||||||
content : string;
|
|
||||||
source: Source;
|
|
||||||
publishedAt : Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getTestNews (): NewsItem[] {
|
export function getTestNews (): NewsItem[] {
|
||||||
console.warn("Remove getTestNews from production! Only for tests!");
|
console.warn("Remove getTestNews from production! Only for tests!");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user