This commit is contained in:
JesmoDev
2022-05-17 12:40:50 +02:00
parent 78ce67d950
commit bb9232d589
10 changed files with 7474 additions and 112 deletions

View File

@@ -5,9 +5,9 @@
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Lit App</title>
<script type="module" src="/src/my-element.ts"></script>
<script type="module" src="/src/umb-app.ts"></script>
</head>
<body>
<my-element></my-element>
<body class="uui-font uui-text" style="margin: 0; padding: 0">
<umb-app></umb-app>
</body>
</html>

7207
src/Umbraco.Web.UI.Client/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@
"lint": "echo 'TODO: Implement lint'"
},
"dependencies": {
"@umbraco-ui/uui": "^0.2.0",
"lit": "^2.0.2"
},
"devDependencies": {
@@ -18,10 +19,10 @@
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-lit": "^1.6.1",
"eslint-plugin-lit-a11y": "^1.1.0-next.1",
"msw": "^0.39.2",
"prettier": "2.6.2",
"typescript": "^4.5.4",
"vite": "^2.9.9",
"msw": "^0.39.2"
"vite": "^2.9.9"
},
"msw": {
"workerDirectory": "public"

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1180 316"><path d="M.2 157.8C.3 70.6 71.1-.1 158.3.1S316.2 71 316.1 158.2s-70.8 157.7-157.9 157.7C70.8 315.9.1 245.1.2 157.8zm154.7 54.1c-12.3.4-24.5-.7-36.5-3.3-8.8-1.8-16.3-7.8-19.9-16-3.6-8.2-5.3-20.9-5.2-38.1.1-9 .6-17.9 1.7-26.8 1-8.7 2.1-15.8 3.1-21.5l1.1-5.6v-.5c0-1.6-1.1-2.9-2.6-3.2l-20.4-3.2h-.4c-1.5 0-2.8 1-3.1 2.5-.3 1.3-.6 2.3-1.2 5.4-1.2 6-2.2 11.8-3.4 20.4-1.3 9.3-2 18.6-2.3 27.9-.4 6.5-.4 13 0 19.6.5 17.3 3.4 31.1 8.9 41.4 5.5 10.3 14.7 17.8 27.7 22.3s31.2 6.8 54.4 6.7h2.9c23.3.1 41.4-2.1 54.4-6.7 13-4.5 22.2-12 27.7-22.3s8.4-24.1 8.9-41.4c.4-6.5.4-13 0-19.6-.3-9.3-1-18.7-2.3-27.9-1.2-8.4-2.3-14.3-3.4-20.4-.6-3.1-.8-4.1-1.2-5.4-.3-1.4-1.6-2.5-3.1-2.5h-.5l-20.4 3.2c-1.6.3-2.7 1.6-2.7 3.2v.5l1.1 5.6c1 5.6 2.1 12.8 3.1 21.5 1 8.9 1.6 17.9 1.7 26.8.2 17.1-1.6 29.8-5.2 38.1-3.6 8.2-11 14.2-19.8 16.1-12 2.5-24.2 3.6-36.5 3.3l-6.6-.1zm932.3-43.9c0-30.4 8.6-51.7 43.8-51.7s43.8 21.3 43.8 51.7-8.6 51.7-43.8 51.7-43.8-21.3-43.8-51.7zm65.3 0c0-21.1-2.7-33.1-21.5-33.1s-21.5 12-21.5 33.1 2.8 33.1 21.5 33.1c18.8 0 21.5-12 21.5-33.1zm-672.1 47.8c.5.9 1.5 1.5 2.5 1.4h8.2c1.6 0 2.9-1.3 2.9-2.9v-92.7c0-1.6-1.3-2.9-2.9-2.9h-16.3c-1.6 0-2.9 1.3-2.9 2.9v73.6c-7 3.9-14.9 5.9-22.8 5.8-10.4 0-15.6-4.5-15.6-14.6v-64.8c0-1.6-1.3-2.9-2.9-2.9h-16.4c-1.6 0-2.9 1.3-2.9 2.9v66.7c0 18.9 8.9 31.3 33.9 31.3 11.4-.1 22.6-3.7 32-10.2l2.9 6.5.3-.1zm184.1-68.1c0-18.7-9.3-31.4-32.6-31.4-11.3 0-22.3 3.4-31.6 9.8-4.1-6.1-12-9.8-25.3-9.8-10.7.2-21.1 3.8-29.7 10.2l-2.9-6.5c-.5-.9-1.5-1.5-2.5-1.4h-8.3c-1.6 0-2.9 1.3-2.9 2.9v92.8c0 1.6 1.3 2.9 2.9 2.9h16.3c1.6 0 2.9-1.3 2.9-2.9v-73.5c6.2-3.8 13.4-5.8 20.7-5.8 8.9 0 14 3.3 14 12.6v66.7c0 1.6 1.3 2.9 2.9 2.9h16.3c1.6 0 2.9-1.3 2.9-2.9v-73.6c6.2-3.9 13.4-5.9 20.7-5.8 8.6 0 14 3.3 14 12.6v66.7c0 1.6 1.3 2.9 2.9 2.9h16.3c1.6 0 2.9-1.3 2.9-2.9l.1-66.5zm50.4 61.7c9.3 6.9 20.5 10.5 32 10.2 28.8 0 39.4-19.3 39.4-51.7s-10.7-51.7-39.4-51.7c-9.4 0-18.5 2.7-26.4 7.7V94.2c0-1.6-1.2-2.9-2.8-3h-16.6c-1.6 0-2.9 1.3-2.9 2.9v120.3c0 1.6 1.3 2.9 2.9 2.9h8.2c1 0 2-.5 2.5-1.4l3.1-6.5zm26.8-8.5c-7.5 0-14.8-2-21.3-5.8v-54.4c6.5-3.8 13.8-5.8 21.3-5.8 19.3 0 22.3 14.8 22.3 32.9s-2.8 33.1-22.3 33.1zM868 135.7c-2.5-.3-5.1-.5-7.7-.5-8.8-.4-17.5 1.7-25.3 5.9v73.2c0 1.6-1.3 2.9-2.9 2.9h-16.3c-1.6 0-2.9-1.3-2.9-2.9v-92.7c0-1.6 1.3-2.9 2.9-2.9h8.2c1 0 2 .5 2.5 1.4l2.9 6.5c8.9-6.8 19.9-10.4 31.2-10.2 2.6 0 5.2.2 7.7.6 1.4 0 2.7 2.4 2.7 4v11.8c0 1.6-1.3 2.9-2.9 2.9h-.2m56.7 36.1c-9.8 1.2-15.6 4.9-15.6 15.2 0 7.5 3.3 14.6 15.2 14.6 7.5.1 14.9-2.2 21.1-6.5v-25.5l-20.7 2.2zm26.1 37.6c-8.5 6.7-19 10.3-29.8 10.2-25.5 0-33.9-15.8-33.9-31.6 0-21.3 13.8-30.4 36.1-32.1l22.1-1.8v-4.9c0-10.1-4.7-14-19.3-14-9.2 0-18.3 1.5-26.9 4.5h-.9c-1.6 0-2.9-1.3-2.9-2.9v-13.1c0-1.2.7-2.4 1.9-2.8 9.8-3.3 20.1-5 30.5-4.9 32.3 0 39.8 14.2 39.8 35.1V214c0 1.6-1.3 2.9-2.9 2.9h-8.2c-1 0-2-.5-2.5-1.4l-3.1-6.1zM1063 197h.9c1.6 0 2.9 1.3 2.9 2.9V213c0 1.2-.7 2.3-1.8 2.7-8.1 2.9-16.7 4.3-25.4 4.1-34.9 0-45.7-20.9-45.7-51.7s10.7-51.7 45.7-51.7c8.6-.2 17.1 1.1 25.2 4 1.1.4 1.9 1.5 1.8 2.7v13.1c0 1.6-1.3 2.9-2.9 2.9h-.9c-7.1-2.2-14.6-3.3-22-3.1-19.1 0-24.7 13.1-24.7 32.2s5.5 32.1 24.7 32.1c7.5.1 14.9-1 22-3.3" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 315.89 315.89"><path fill="#fff" d="M0 157.74a157.95 157.95 0 11158 158.15A157.95 157.95 0 010 157.74zm154.74 54.09a155.41 155.41 0 01-36.5-3.29 27.92 27.92 0 01-19.94-16q-5.35-12.34-5.21-38.1a243 243 0 011.69-26.84q1.55-13 3.09-21.46l1.07-5.59a2 2 0 000-.49 3.2 3.2 0 00-2.65-3.17l-20.37-3.22h-.44a3.19 3.19 0 00-3.11 2.48c-.35 1.31-.56 2.27-1.17 5.38-1.16 6-2.24 11.85-3.43 20.38a264.17 264.17 0 00-2.3 27.94 145.24 145.24 0 000 19.57q.72 25.94 8.9 41.42t27.72 22.3q19.53 6.81 54.43 6.66h2.91q34.94.15 54.41-6.66t27.71-22.3q8.17-15.53 8.91-41.42a145.24 145.24 0 000-19.57 266.84 266.84 0 00-2.3-27.94c-1.2-8.44-2.27-14.26-3.44-20.38-.61-3.11-.81-4.07-1.16-5.38a3.21 3.21 0 00-3.12-2.48h-.52l-20.38 3.18a3.2 3.2 0 00-2.68 3.17 4 4 0 000 .49l1.08 5.59q1.55 8.48 3.12 21.46a245.68 245.68 0 011.65 26.84q.27 25.69-5.21 38.07a27.9 27.9 0 01-19.76 16.07 155.19 155.19 0 01-36.48 3.29z"/></svg>

After

Width:  |  Height:  |  Size: 942 B

View File

@@ -0,0 +1,117 @@
import { html, css, LitElement, CSSResultGroup } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { UUITextStyles } from '@umbraco-ui/uui-css';
import { ifDefined } from 'lit/directives/if-defined.js';
// create custom element with lit-element named 'umb-login'
@customElement('umb-login')
export class UmbLogin extends LitElement {
static styles: CSSResultGroup = [
UUITextStyles,
css`
#email,
#password {
width: 100%;
}
`,
];
@state()
private _loggingIn = false;
private _handleSubmit = (e: SubmitEvent) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
if (!form) return;
const isValid = form.checkValidity();
if (!isValid) return;
const formData = new FormData(form);
const username = formData.get('email') as string;
const password = formData.get('password') as string;
const persist = formData.has('persist');
this._login(username, password, persist);
};
private async _login(username: string, password: string, persist: boolean) {
console.log('LOGIN', username, password, persist);
this._loggingIn = true;
try {
await fetch('/login', { method: 'POST' });
this._loggingIn = false;
// TODO: Change to redirect when router has been added.
this.dispatchEvent(new CustomEvent('login', { detail: { username, password, persist } }));
} catch (error) {
console.log(error);
this._loggingIn = false;
}
}
private _greetings: Array<string> = [
'Happy super Sunday',
'Happy manic Monday',
'Happy tubular Tuesday',
'Happy wonderful Wednesday',
'Happy thunderous Thursday',
'Happy funky Friday',
'Happy Caturday',
];
@state()
private _greeting: string = this._greetings[new Date().getDay()];
render() {
return html`
<div class="uui-text">
<h1 class="uui-h3">${this._greeting}</h1>
<uui-form>
<form id="LoginForm" name="login" @submit="${this._handleSubmit}">
<uui-form-layout-item>
<uui-label for="email" slot="label" required>Email</uui-label>
<uui-input
type="email"
id="email"
name="email"
placeholder="Enter your email..."
required
required-message="Email is required"></uui-input>
</uui-form-layout-item>
<uui-form-layout-item>
<uui-label for="password" slot="label" required>Password</uui-label>
<uui-input-password
id="password"
name="password"
placeholder="Enter your password..."
required
required-message="Password is required"></uui-input-password>
</uui-form-layout-item>
<uui-form-layout-item>
<uui-checkbox name="persist" label="Remember me"> Remember me </uui-checkbox>
</uui-form-layout-item>
<uui-button
type="submit"
label="Login"
look="positive"
state=${ifDefined(this._loggingIn ? 'waiting' : undefined)}></uui-button>
<uui-button type="button" label="Forgot Password?"></uui-button>
</form>
</uui-form>
</div>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'umb-login': UmbLogin;
}
}

View File

@@ -0,0 +1,72 @@
import { css, CSSResultGroup, html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
@customElement('umb-auth-layout')
export class UmbAuthLayout extends LitElement {
static styles: CSSResultGroup = [
css`
#background {
position: fixed;
overflow: hidden;
background-position: 50%;
background-repeat: no-repeat;
background-size: cover;
background-image: url('/login.jpeg');
width: 100vw;
height: 100vh;
}
#logo {
position: fixed;
top: var(--uui-size-space-5);
left: var(--uui-size-space-5);
height: 30px;
}
#logo img {
height: 100%;
}
#container {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
}
#box {
width: 500px;
padding: var(--uui-size-space-6) var(--uui-size-space-5) var(--uui-size-space-5) var(--uui-size-space-5);
}
#email,
#password {
width: 100%;
}
`,
];
render() {
return html`
<div id="background"></div>
<div id="logo">
<img src="/umbraco_logo_white.svg" alt="Umbraco" />
</div>
<div id="container">
<uui-box id="box">
<slot></slot>
</uui-box>
</div>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'umb-auth-layout': UmbAuthLayout;
}
}

View File

@@ -1,107 +0,0 @@
import { html, css, LitElement } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { worker } from './mocks/browser';
/**
* An example element.
*
* @slot - This element has a slot
* @csspart button - The button
*/
@customElement('my-element')
export class MyElement extends LitElement {
static styles = css`
:host {
display: block;
border: solid 1px gray;
padding: 16px;
max-width: 800px;
}
`;
/**
* The name to say "Hello" to.
*/
@property()
name = 'World';
/**
* The number of times the button has been clicked.
*/
@property({ type: Number })
count = 0;
@state()
_authorized = false;
@state()
_user: any;
constructor() {
super();
worker.start();
}
private async _onLogin() {
try {
await fetch('/login', { method: 'POST' });
this._authorized = true;
this._getUser();
} catch (error) {
console.log(error);
}
}
private _onLogout() {
try {
fetch('/logout', { method: 'POST' });
this._authorized = false;
} catch (error) {
console.log(error);
}
}
private async _getUser() {
try {
const res = await fetch('/user');
this._user = await res.json();
} catch (error) {
console.log(error);
}
}
render() {
return html`
<h1>Hello, ${this.name}!</h1>
<button @click=${this._onClick} part="button">Click Count: ${this.count}</button>
<h2>Login Here</h2>
${this._authorized
? html`<button @click=${this._onLogout}>Logout</button>`
: html`<button @click=${this._onLogin}>Login</button>`}
${this._authorized && this._user
? html`
<h3>User information</h3>
<div>Username: ${this._user.username}</div>
`
: ''}
<slot></slot>
`;
}
private _onClick() {
this.count++;
fetch('/login', { method: 'POST' });
}
foo(): string {
return 'foo';
}
}
declare global {
interface HTMLElementTagNameMap {
'my-element': MyElement;
}
}

View File

@@ -0,0 +1,70 @@
import '@umbraco-ui/uui-css/dist/uui-css.css';
import { html, css, LitElement } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { worker } from './mocks/browser';
// Import somewhere else?
import '@umbraco-ui/uui';
import './auth/login/umb-login.element';
import './auth/umb-auth-layout.element';
@customElement('umb-app')
export class UmbApp extends LitElement {
static styles = css`
:host {
width: 100vw;
height: 100vh;
}
`;
@state()
_authorized = false;
@state()
_user: any;
constructor() {
super();
worker.start();
}
private _onLogout() {
try {
fetch('/logout', { method: 'POST' });
this._authorized = false;
} catch (error) {
console.log(error);
}
}
private async _getUser() {
try {
const res = await fetch('/user');
this._user = await res.json();
} catch (error) {
console.log(error);
}
}
private _handleLogin = () => {
this._authorized = true;
this._getUser();
};
render() {
return html`
${!this._authorized
? html`<umb-auth-layout>
<umb-login @login=${this._handleLogin}></umb-login>
</umb-auth-layout>`
: html`hej`}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'umb-app': UmbApp;
}
}