diff --git a/public/index.html b/public/index.html index cadb330a..9d7af112 100644 --- a/public/index.html +++ b/public/index.html @@ -20,6 +20,7 @@ "/admin/settings": "/pages/adminpage/ctrl_settings.js", "/admin/logs": "/pages/adminpage/ctrl_logger.js", "/admin/about": "/pages/adminpage/ctrl_about.js", + "/admin/setup": "/pages/adminpage/ctrl_setup.js", "/admin/": "/pages/adminpage/ctrl_home.js", "/logout": "/pages/ctrl_logout.js", diff --git a/public/pages/adminpage/ctrl_setup.css b/public/pages/adminpage/ctrl_setup.css new file mode 100644 index 00000000..353607a9 --- /dev/null +++ b/public/pages/adminpage/ctrl_setup.css @@ -0,0 +1,79 @@ +.component_setup { + transform: none !important; +} +.component_setup h4 { + user-select: none; + text-align: center; + font-size: 1.4em; + font-weight: 500; + padding: 20px 0 0px 0; +} +.component_setup h4 .component_icon { + vertical-align: text-top; + width: 1.3em; + cursor: pointer; +} +.component_setup h4 .component_icon[alt="loading"] { + opacity: 0; +} +.component_setup #step1 p { + font-size: 1.1em; + margin-bottom: 10px; +} +.component_setup #step1 form { + max-width: 400px; +} +.component_setup #step1 form { + display: flex; + background: white; + border-radius: 2px; + box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1); +} +.component_setup #step1 form input { + padding: 15px 20px; + border-bottom: 0; + margin: 0; + height: inherit !important; +} +.component_setup #step1 form button { + width: inherit; + padding: 0 10px; +} +.component_setup #step1 form button .component_icon { + height: 25px; +} +.component_setup #step2 .component_dependency_installed { + margin: 10px 0; + padding: 10px 10px; + border-radius: 3px; + color: rgba(0, 0, 0, 0.6); +} +.component_setup #step2 .component_dependency_installed.yes { + background: var(--success); +} +.component_setup #step2 .component_dependency_installed.no { + background: var(--primary); +} +.component_setup #step2 .component_dependency_installed.no.severe { + background: var(--error); +} +.component_setup #step2 .component_dependency_installed.no.severe span { + font-weight: bold; + font-style: italic; +} +.component_setup .stepper-form-appear, .component_setup .stepper-form-enter { + transition-delay: 0.3s; + transform: scale(1.02); + opacity: 0; + transition: all 0.3s ease; +} +.component_setup .stepper-form-appear.stepper-form-appear-active, +.component_setup .stepper-form-appear.stepper-form-enter-active, +.component_setup .stepper-form-enter.stepper-form-appear-active, +.component_setup .stepper-form-enter.stepper-form-enter-active { + opacity: 1; + transform: scale(1); +} +.component_setup .component_icon { + width: 30px; +} diff --git a/public/pages/adminpage/ctrl_setup.js b/public/pages/adminpage/ctrl_setup.js index 18108df6..c177742d 100644 --- a/public/pages/adminpage/ctrl_setup.js +++ b/public/pages/adminpage/ctrl_setup.js @@ -1,6 +1,137 @@ -import { createElement } from "../../lib/skeleton/index.js"; +import { createElement, createRender } from "../../lib/skeleton/index.js"; +import rxjs, { effect, stateMutation, applyMutation, preventDefault } from "../../lib/rxjs/index.js"; +import { qs } from "../../lib/dom/index.js"; +import { ApplicationError } from "../../lib/error/index.js"; +import { transition, opacityOut } from "../../lib/animate/index.js"; -export default function(render) { +import CSSLoader from "../../helpers/css.js"; +import ctrlError from "../ctrl_error.js"; +import WithShell from "./decorator_sidemenu.js"; +import { zoomIn } from "./animate.js"; + +import "../../components/icon.js"; + +const stepper$ = new rxjs.BehaviorSubject(1); + +export default function(render) { + const $page = createElement(` +
+
+ +
+ `); + render($page); + + effect(stepper$.pipe( + dbg("CHANGE"), + rxjs.map((step) => { + switch(step) { + case 1: return WithShell(componentStep1); + case 2: return WithShell(componentStep2); + default: throw new ApplicationError("INTERNAL_ERROR", "Assumption failed"); + } + }), + rxjs.tap((ctrl) => ctrl(createRender(qs($page, `[data-bind="multistep-form"]`)))), + rxjs.catchError((err) => ctrlError(err)(render)), + )); +}; + +const cssHideMenu = `.component_menu_sidebar{transform: translateX(-300px)}`; + +function componentStep1(render) { + const $page = createElement(` +
+

Admin Password

+
+

Create your instance admin password:

+
+ + +
+
+ +
+ `); + render(transition($page, { + timeoutEnter: 250, enter: zoomIn(1.2), + timeoutLeave: 0, + })); + render($page); + + // feature: form handling + effect(rxjs.fromEvent(qs($page, "form"), "submit").pipe( + preventDefault(), + rxjs.mapTo(["name", "loading"]), applyMutation(qs($page, "component-icon"), "setAttribute"), + rxjs.map(() => qs($page, "input").value), + rxjs.delay(1000), + dbg("SUBMIT"), + animateOut($page), + dbg("after merge"), + rxjs.tap(() => stepper$.next(2)), + )); + + // feature: autofocus + effect(rxjs.of([]).pipe( + applyMutation(qs($page, "input"), "focus"), + )); } -// const css = await CSSLoader(import.meta, "ctrl_setup.css"); +function componentStep2(render) { + const deps = []; + const $page = createElement(` +
+

+ + Summary +

+ ${deps.map((t) => t.label).join("")} + +
`); + render($page); + + // feature: navigate previous step + effect(rxjs.fromEvent(qs($page, `[data-bind="previous"]`), "click").pipe( + dbg("click"), + rxjs.tap(() => stepper$.next(1)), + )); + + // feature: animate the screen + effect(rxjs.of([]).pipe( + rxjs.tap(() => qs($page, "h4").animate([ + { transform: "translateX(30px)", opacity: "0"}, + { transform: "translateX(0px)", opacity: "1"}, + ], { + duration: 200, + fill: "forwards", + })), + rxjs.delay(200), + applyMutation(qs($page, "style"), "remove"), + dbg("") + )); + + + // feature: opt in for telemetry + // onDestroy() +} + +const animateOut = ($el) => { + return rxjs.pipe( + dbg("animate: "+ opacityOut()), + // rxjs.tap(() => transition($el, { + // timeoutEnter: 500, enter: opacityOut(), + // timeoutLeave: 0, + // })), + rxjs.tap(() => $el.animate([ + { transform: "translateX(0px)", opacity: "1"}, + { transform: "translateX(-30px)", opacity: "0"}, + ], { + duration: 300, + fill: "forwards", + })), + rxjs.delay(200), + ); +} + +const css = await CSSLoader(import.meta, "ctrl_setup.css"); diff --git a/public/pages/adminpage/decorator_sidemenu.css b/public/pages/adminpage/decorator_sidemenu.css index 6b1df242..07efe338 100644 --- a/public/pages/adminpage/decorator_sidemenu.css +++ b/public/pages/adminpage/decorator_sidemenu.css @@ -5,7 +5,7 @@ border-right: 2px solid var(--color); padding: 50px 0px 0px 40px; transition: transform 0.3s ease; - transition-delay: 0.7s; + transition-delay: 0s; flex-shrink: 0; } .component_menu_sidebar h2 {