diff --git a/src/Umbraco.Web.UI.Client/public/installer.jpg b/src/Umbraco.Web.UI.Client/public/installer.jpg
new file mode 100644
index 0000000000..f0f5de8695
Binary files /dev/null and b/src/Umbraco.Web.UI.Client/public/installer.jpg differ
diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer-database.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer-database.element.ts
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer-layout.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer-layout.element.ts
new file mode 100644
index 0000000000..c447c51f71
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/installer-layout.element.ts
@@ -0,0 +1,67 @@
+import { css, CSSResultGroup, html, LitElement } from 'lit';
+import { customElement } from 'lit/decorators.js';
+
+@customElement('umb-installer-layout')
+export class UmbInstallerLayout extends LitElement {
+ static styles: CSSResultGroup = [
+ css`
+ #background {
+ position: fixed;
+ overflow: hidden;
+ background-position: 50%;
+ background-repeat: no-repeat;
+ background-size: cover;
+ background-image: url('/installer.jpg');
+ 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: 300px;
+ padding: var(--uui-size-space-6) var(--uui-size-space-5) var(--uui-size-space-5) var(--uui-size-space-5);
+ }
+ `,
+ ];
+
+ render() {
+ return html`
+
+
+
+

+
+
+
+
+
+
+
+
`;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-installer-layout': UmbInstallerLayout;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer-user.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer-user.element.ts
new file mode 100644
index 0000000000..5b489471a5
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/installer/installer-user.element.ts
@@ -0,0 +1,100 @@
+import { css, CSSResultGroup, html, LitElement } from 'lit';
+import { customElement, state } from 'lit/decorators.js';
+
+@customElement('umb-installer-user')
+export class UmbInstallerUser extends LitElement {
+ static styles: CSSResultGroup = [
+ css`
+ uui-input,
+ uui-input-password {
+ width: 100%;
+ }
+ `,
+ ];
+
+ 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 name = formData.get('name') as string;
+ const email = formData.get('email') as string;
+ const password = formData.get('password') as string;
+ const news = formData.has('news');
+
+ this._install(name, email, password, news);
+ };
+
+ private async _install(name: string, email: string, password: string, news: boolean) {
+ console.log('Installing', name, email, password, news);
+
+ try {
+ await fetch('/install', { method: 'POST' });
+
+ // TODO: Change to redirect when router has been added.
+ this.dispatchEvent(new CustomEvent('install', { bubbles: true, composed: true }));
+ } catch (error) {
+ console.log(error);
+ }
+ }
+
+ render() {
+ return html`
+
Install Umbraco
+
+
+
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-installer-user': UmbInstallerUser;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer.element.ts
index c0cc7a1b8f..7421b6d722 100644
--- a/src/Umbraco.Web.UI.Client/src/installer/installer.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/installer/installer.element.ts
@@ -1,14 +1,43 @@
import { css, CSSResultGroup, html, LitElement } from 'lit';
-import { customElement } from 'lit/decorators.js';
+import { customElement, state } from 'lit/decorators.js';
+import './installer-layout.element';
+import './installer-user.element';
@customElement('umb-installer')
export class UmbInstaller extends LitElement {
- static styles: CSSResultGroup = [
- css``,
- ];
+ static styles: CSSResultGroup = [css``];
+
+ @state()
+ step = 1;
+
+ private _renderSection() {
+ switch (this.step) {
+ case 2:
+ return html`database
`;
+ case 3:
+ return html`installing
`;
+
+ default:
+ return html``;
+ }
+ }
+
+ connectedCallback(): void {
+ super.connectedCallback();
+ this.addEventListener('install', () => this._handleInstall());
+ }
+
+ private _handleInstall() {
+ this.step++;
+ }
render() {
- return html`Installer
`;
+ return html`${this._renderSection()}
+
+ this.step--}>Back
+ this.step++}>Next
+ `;
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers.ts
index 3422fef735..5e46348369 100644
--- a/src/Umbraco.Web.UI.Client/src/mocks/handlers.ts
+++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers.ts
@@ -7,9 +7,9 @@ export const handlers = [
ctx.status(200),
ctx.json({
version: 'x.x.x',
- installed: true
- }),
- )
+ installed: false,
+ })
+ );
}),
rest.post('/login', (_req, res, ctx) => {
@@ -17,8 +17,8 @@ export const handlers = [
sessionStorage.setItem('is-authenticated', 'true');
return res(
// Respond with a 200 status code
- ctx.status(200),
- )
+ ctx.status(200)
+ );
}),
rest.post('/logout', (_req, res, ctx) => {
@@ -26,8 +26,8 @@ export const handlers = [
sessionStorage.removeItem('is-authenticated');
return res(
// Respond with a 200 status code
- ctx.status(200),
- )
+ ctx.status(200)
+ );
}),
rest.get('/user', (_req, res, ctx) => {
@@ -39,15 +39,22 @@ export const handlers = [
ctx.status(403),
ctx.json({
errorMessage: 'Not authorized',
- }),
- )
+ })
+ );
}
// If authenticated, return a mocked user details
return res(
ctx.status(200),
ctx.json({
username: 'admin',
- }),
- )
+ })
+ );
}),
-];
\ No newline at end of file
+
+ rest.post('/install', (_req, res, ctx) => {
+ return res(
+ // Respond with a 200 status code
+ ctx.status(200)
+ );
+ }),
+];