feature (admin): setup page

This commit is contained in:
Mickael Kerjean 2023-07-24 17:59:53 +10:00
parent 1c1f8b5052
commit 4217fb9ca3
4 changed files with 215 additions and 4 deletions

View file

@ -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",

View file

@ -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;
}

View file

@ -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(`
<div class="component_setup">
<div data-bind="multistep-form"></div>
<style>${css}</style>
</div>
`);
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(`
<div id="step1">
<h4>Admin Password</h4>
<div>
<p>Create your instance admin password: </p>
<form>
<input class="component_input" type="password" placeholder="Password" />
<button theme="transparent">
<component-icon name="arrow_right"></component-icon>
</button>
</form>
</div>
<style>${cssHideMenu}</style>
</div>
`);
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(`
<div id="step2">
<h4>
<component-icon name="arrow_left" data-bind="previous"></component-icon>
Summary
</h4>
${deps.map((t) => t.label).join("")}
<style>${cssHideMenu}</style>
</div>`);
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");

View file

@ -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 {