Generated project

This commit is contained in:
start.vaadin.com
2021-07-25 10:44:30 +00:00
commit 6e3f448aa3
50 changed files with 10663 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { View } from '../../views/view';
@customElement('admin-view')
export class AdminView extends View {
render() {
return html`<div>Content placeholder</div>`;
}
}

View File

@@ -0,0 +1,10 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { View } from '../../views/view';
@customElement('home-view')
export class HomeView extends View {
render() {
return html`<div>Content placeholder</div>`;
}
}

View File

@@ -0,0 +1,40 @@
import '@vaadin/vaadin-login';
import { LoginI18n } from '@vaadin/vaadin-login';
import { html } from 'lit';
import { customElement, state } from 'lit/decorators';
import { View } from '../../views/view';
const loginI18nDefault: LoginI18n = {
form: {
title: 'Log in',
username: 'Username',
password: 'Password',
submit: 'Log in',
forgotPassword: 'Forgot password',
},
errorMessage: {
title: 'Incorrect username or password',
message: 'Check that you have entered the correct username and password and try again.',
},
};
@customElement('login-view')
export class LoginView extends View {
@state()
private error = false;
render() {
return html`
<vaadin-login-overlay
opened
.error=${this.error}
action="login"
no-forgot-password
.i18n=${Object.assign(
{ header: { title: 'Fusion Management', description: 'Login using user/user or admin/admin' } },
loginI18nDefault
)}
>
</vaadin-login-overlay>
`;
}
}

View File

@@ -0,0 +1,83 @@
import '@vaadin/vaadin-app-layout';
import { AppLayoutElement } from '@vaadin/vaadin-app-layout';
import '@vaadin/vaadin-app-layout/vaadin-drawer-toggle';
import '@vaadin/vaadin-avatar/vaadin-avatar';
import '@vaadin/vaadin-context-menu';
import '@vaadin/vaadin-tabs';
import '@vaadin/vaadin-tabs/vaadin-tab';
import '@vaadin/vaadin-template-renderer';
import { html, render } from 'lit';
import { customElement } from 'lit/decorators.js';
import { logout } from '../auth';
import { router } from '../index';
import { hasAccess, views } from '../routes';
import { appStore } from '../stores/app-store';
import { Layout } from './view';
interface RouteInfo {
path: string;
title: string;
icon: string;
}
@customElement('main-layout')
export class MainLayout extends Layout {
render() {
return html`
<vaadin-app-layout primary-section="drawer">
<header slot="navbar" theme="dark" class="sidemenu-header">
<vaadin-drawer-toggle></vaadin-drawer-toggle>
<h1>${appStore.currentViewTitle}</h1>
${appStore.user
? html` <vaadin-context-menu class="ms-auto me-m" open-on="click" .renderer="${this.renderLogoutOptions}">
<vaadin-avatar img="${appStore.user.profilePictureUrl}" name="${appStore.user.name}"></vaadin-avatar
></vaadin-context-menu>`
: html`<a class="ms-auto me-m" router-ignore href="login">Sign in</a>`}
</header>
<div slot="drawer" class="sidemenu-menu">
<div id="logo">
<img src="images/logo.png" alt="${appStore.applicationName} logo" />
<span>${appStore.applicationName}</span>
</div>
<hr />
<vaadin-tabs orientation="vertical" theme="minimal" .selected=${this.getSelectedViewRoute()}>
${this.getMenuRoutes().map(
(viewRoute) => html`
<vaadin-tab>
<span class="${viewRoute.icon} pr-s"></span>
<a href=${router.urlForPath(viewRoute.path)} tabindex="-1">${viewRoute.title}</a>
</vaadin-tab>
`
)}
</vaadin-tabs>
</div>
<slot></slot>
</vaadin-app-layout>
`;
}
connectedCallback() {
super.connectedCallback();
this.classList.add('block', 'h-full');
this.reaction(
() => appStore.location,
() => {
AppLayoutElement.dispatchCloseOverlayDrawerEvent();
}
);
}
private renderLogoutOptions(root: HTMLElement) {
render(html`<vaadin-list-box><vaadin-item @click=${() => logout()}>Logout</vaadin-item></vaadin-list-box>`, root);
}
private getMenuRoutes(): RouteInfo[] {
return views.filter((route) => route.title).filter((route) => hasAccess(route)) as RouteInfo[];
}
private getSelectedViewRoute(): number {
const path = appStore.location;
return this.getMenuRoutes().findIndex((viewRoute) => viewRoute.path == path);
}
}

View File

@@ -0,0 +1,10 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { View } from '../../views/view';
@customElement('profile-view')
export class ProfileView extends View {
render() {
return html`<div>Content placeholder</div>`;
}
}

51
frontend/views/view.ts Normal file
View File

@@ -0,0 +1,51 @@
import { MobxLitElement } from '@adobe/lit-mobx';
import { applyTheme } from 'Frontend/generated/theme';
import { autorun, IAutorunOptions, IReactionDisposer, IReactionOptions, IReactionPublic, reaction } from 'mobx';
export class MobxElement extends MobxLitElement {
private disposers: IReactionDisposer[] = [];
/**
* Creates a MobX reaction using the given parameters and disposes it when this element is detached.
*
* This should be called from `connectedCallback` to ensure that the reaction is active also if the element is attached again later.
*/
protected reaction<T>(
expression: (r: IReactionPublic) => T,
effect: (arg: T, prev: T, r: IReactionPublic) => void,
opts?: IReactionOptions
): void {
this.disposers.push(reaction(expression, effect, opts));
}
/**
* Creates a MobX autorun using the given parameters and disposes it when this element is detached.
*
* This should be called from `connectedCallback` to ensure that the reaction is active also if the element is attached again later.
*/
protected autorun(view: (r: IReactionPublic) => any, opts?: IAutorunOptions): void {
this.disposers.push(autorun(view, opts));
}
disconnectedCallback() {
super.disconnectedCallback();
this.disposers.forEach((disposer) => {
disposer();
});
this.disposers = [];
}
}
export class View extends MobxElement {
createRenderRoot() {
// Do not use a shadow root
return this;
}
}
export class Layout extends MobxElement {
connectedCallback() {
super.connectedCallback();
applyTheme(this.shadowRoot!);
}
}