Setup Screen: Use StepsWrapper

Similar to TabsWrapper, with Previous/Next navigation capabilities.
This commit is contained in:
Francesco Siddi 2022-07-20 18:15:37 +02:00
parent a075a36911
commit 8b02085c5b
3 changed files with 218 additions and 184 deletions

View File

@ -0,0 +1,13 @@
<script setup>
import { inject } from 'vue';
const props = defineProps({
title: String,
});
const selectedStep = inject('selectedStep');
</script>
<template>
<div v-show="selectedStep === title">
<slot />
</div>
</template>

View File

@ -0,0 +1,124 @@
<script setup>
import { useSlots, ref, provide } from 'vue';
const slots = useSlots();
const stepTitles = ref(slots.default().map((step) => step.props.title));
const selectedStep = ref(stepTitles.value[0]);
provide('selectedStep', selectedStep);
function updateStepTitle(title) {
selectedStep.value = title;
}
function selectedStepNumber() {
return stepTitles.value.indexOf(selectedStep.value);
}
function nextStepTitle() {
selectedStep.value = stepTitles.value[selectedStepNumber() + 1];
}
function prevStepTitle() {
selectedStep.value = stepTitles.value[selectedStepNumber() - 1];
}
</script>
<template>
<div class="setup-step">
<h2>{{ selectedStep }}</h2>
<nav>
<ul class="progress">
<li
v-for="(title, index) in stepTitles"
:class="{active: selectedStep == title}"
@click="updateStepTitle(title)"
>
<span></span>
</li>
</ul>
</nav>
<slot />
<div
v-if="selectedStepNumber() != stepTitles.length - 1"
class="btn-bar btn-bar-wide">
<button
v-if="selectedStepNumber() > 0"
@click="prevStepTitle()"
class="btn">Back
</button>
<button
@click="nextStepTitle()"
class="btn btn-primary">Next</button>
</div>
</div>
</template>
<style scoped>
.progress {
--wiz-progress-indicator-size: 8px;
--wiz-progress-indicator-border-width: 2px;
--wiz-progress-indicator-color: var(--color-text-hint);
--wiz-progress-indicator-color-active: var(--color-accent);
display: flex;
justify-content: space-between;
list-style: none;
margin-bottom: 2rem;
padding: 0;
position: relative;
}
/* Progress indicator dot. */
.progress li {
cursor: pointer;
}
.progress li span {
background-color: var(--wiz-progress-indicator-color);
border-radius: 50%;
border: var(--wiz-progress-indicator-border-width) solid var(--color-background-column);
box-shadow: 0 0 0 var(--wiz-progress-indicator-border-width) var(--wiz-progress-indicator-color);
content: '';
cursor: pointer;
display: block;
height: var(--wiz-progress-indicator-size);
position: relative;
width: var(--wiz-progress-indicator-size);
}
.progress li.active span {
background-color: var(--color-accent);
box-shadow: 0 0 0 var(--wiz-progress-indicator-border-width) var(--wiz-progress-indicator-color-active);
}
.progress li.active+li span,
.progress li.active+li+li span {
background-color: var(--color-background-column);
}
/* Progress indicator line between dots. */
.progress:before {
background-color: var(--wiz-progress-indicator-color);
content: '';
display: block;
height: var(--wiz-progress-indicator-border-width);
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
}
.setup-step {
background-color: var(--color-background-column);
border-radius: var(--border-radius);
padding: var(--spacer) var(--spacer-lg);
}
</style>

View File

@ -1,131 +1,90 @@
<template> <template>
<div class="setup-container"> <div class="setup-container">
<section class="setup-step step-intro is-active"> <steps-wrapper>
<h1>Welcome</h1> <step-item title="Welcome">
<p>Let's set you up.</p>
</step-item>
<ul class="progress"> <step-item title="Shared Storage">
<li class="active"><span></span></li> <p>Flamenco needs some shared storage, to have a central place where the
<li><span></span></li> Manager and Workers exchange files. This could be a NAS in your network,
<li><span></span></li> or some other file sharing server.</p>
<li><span></span></li>
</ul>
<p>Let's set you up.</p> <p>Make sure this path is the same for all machines involved.</p>
<div class="btn-bar"> <p class="hint">Using a service like Syncthing, ownCloud, or Dropbox for
<button class="btn btn-primary align-center">Start Setup</button> this is not recommended, as Flamenco does not know when every machine has
</div> received the files.</p>
</section>
<section class="setup-step is-active"> <!-- TODO: @submit.prevent makes the button triggerable by pressing ENTER
<h2>Shared Storage</h2> in the input field, but also prevents the browser from caching
previously-used values. Would be great if we could have both. -->
<form @submit.prevent="checkSharedStoragePath">
<input v-model="sharedStoragePath" type="text">
<button type="submit">Check</button>
</form>
<ul class="progress"> <p v-if="sharedStorageCheckResult != null"
<li><span></span></li> :class="{ 'check-ok': sharedStorageCheckResult.is_usable, 'check-failed': !sharedStorageCheckResult.is_usable }">
<li class="active"><span></span></li> {{ sharedStorageCheckResult.cause }}
<li><span></span></li> </p>
<li><span></span></li> </step-item>
</ul> <step-item title="Blender">
<p>Choose which Blender to use below:</p>
<p>Flamenco needs some shared storage, to have a central place where the <p v-if="isBlenderExeFinding">... finding Blenders ...</p>
Manager and Workers exchange files. This could be a NAS in your network, <div v-for="blender in allBlenders" class="blender-selector"
or some other file sharing server.</p> :class="{ 'selected-blender': (blender == selectedBlender) }">
<dl>
<dt>Version</dt>
<dd>{{ blender.cause }}</dd>
<p>Make sure this path is the same for all machines involved.</p> <dt>Path</dt>
<dd>{{ blender.path }}</dd>
<p class="hint">Using a service like Syncthing, ownCloud, or Dropbox for <dt>Source</dt>
this is not recommended, as Flamenco does not know when every machine has <dd>{{ sourceLabels[blender.source] }}</dd>
received the files.</p> </dl>
<button @click="selectedBlender = blender" :disabled="selectedBlender == blender">Use this Blender</button>
</div>
<!-- TODO: @submit.prevent makes the button triggerable by pressing ENTER <p>Or provide an alternative command to try:</p>
in the input field, but also prevents the browser from caching
previously-used values. Would be great if we could have both. -->
<form @submit.prevent="checkSharedStoragePath">
<input v-model="sharedStoragePath" type="text">
<button type="submit">Check</button>
</form>
<p v-if="sharedStorageCheckResult != null" <form @submit.prevent="checkBlenderExePath">
:class="{ 'check-ok': sharedStorageCheckResult.is_usable, 'check-failed': !sharedStorageCheckResult.is_usable }"> <input v-model="customBlenderExe" type="text">
{{ sharedStorageCheckResult.cause }} <button type="submit">Check</button>
</p> </form>
<p v-if="isBlenderExeChecking">... checking ...</p>
<div class="btn-bar btn-bar-wide"> <p v-if="blenderExeCheckResult != null && blenderExeCheckResult.is_usable" class="check-ok">
<button class="btn">Back</button> Found something, it is selected above.</p>
<button class="btn btn-primary" disabled>Next</button> <p v-if="blenderExeCheckResult != null && !blenderExeCheckResult.is_usable" class="check-failed">
</div> {{ blenderExeCheckResult.cause }}</p>
</section> </step-item>
<step-item title="Review">
<section class="setup-step is-active"> <div v-if="isConfigComplete">
<h2>Which Blender?</h2> <p>This is the configuration that will be used by Flamenco:</p>
<dl>
<ul class="progress"> <dt>Storage</dt>
<li><span></span></li> <dd>{{ sharedStorageCheckResult.path }}</dd>
<li><span></span></li> <dt>Blender</dt>
<li class="active"><span></span></li> <dd v-if="selectedBlender.source == 'file_association'">
<li><span></span></li> Whatever Blender is associated with .blend files
</ul> (currently "<code>{{ selectedBlender.path }}</code>")
</dd>
<p>Choose which Blender to use below:</p> <dd v-if="selectedBlender.source == 'path_envvar'">
The command "<code>{{ selectedBlender.input }}</code>" as found on <code>$PATH</code>
<p v-if="isBlenderExeFinding">... finding Blenders ...</p> (currently "<code>{{ selectedBlender.path }}</code>")
<div v-for="blender in allBlenders" class="blender-selector" </dd>
:class="{ 'selected-blender': (blender == selectedBlender) }"> <dd v-if="selectedBlender.source == 'input_path'">
<dl> The command you provided:
<dt>Version</dt> "<code>{{ selectedBlender.path }}</code>"
<dd>{{ blender.cause }}</dd> </dd>
</dl>
<dt>Path</dt> </div>
<dd>{{ blender.path }}</dd> <p v-if="isConfirmed" class="check-ok">Configuration has been saved, Flamenco will restart.</p>
<button @click="confirmWizard" :disabled="isConfirming">Confirm</button>
<dt>Source</dt> </step-item>
<dd>{{ sourceLabels[blender.source] }}</dd> </steps-wrapper>
</dl>
<button @click="selectedBlender = blender" :disabled="selectedBlender == blender">Use this Blender</button>
</div>
<p>Or provide an alternative command to try:</p>
<form @submit.prevent="checkBlenderExePath">
<input v-model="customBlenderExe" type="text">
<button type="submit">Check</button>
</form>
<p v-if="isBlenderExeChecking">... checking ...</p>
<p v-if="blenderExeCheckResult != null && blenderExeCheckResult.is_usable" class="check-ok">
Found something, it is selected above.</p>
<p v-if="blenderExeCheckResult != null && !blenderExeCheckResult.is_usable" class="check-failed">
{{ blenderExeCheckResult.cause }}</p>
<div class="btn-bar btn-bar-wide">
<button class="btn">Back</button>
<button class="btn btn-primary">Next</button>
</div>
</section>
<section v-if="isConfigComplete" class="setup-step is-active">
<h2>The Final Step</h2>
<p>This is the configuration that will be used by Flamenco:</p>
<dl>
<dt>Storage</dt>
<dd>{{ sharedStorageCheckResult.path }}</dd>
<dt>Blender</dt>
<dd v-if="selectedBlender.source == 'file_association'">
Whatever Blender is associated with .blend files
(currently "<code>{{ selectedBlender.path }}</code>")
</dd>
<dd v-if="selectedBlender.source == 'path_envvar'">
The command "<code>{{ selectedBlender.input }}</code>" as found on <code>$PATH</code>
(currently "<code>{{ selectedBlender.path }}</code>")
</dd>
<dd v-if="selectedBlender.source == 'input_path'">
The command you provided:
"<code>{{ selectedBlender.path }}</code>"
</dd>
</dl>
<p v-if="isConfirmed" class="check-ok">Configuration has been saved, Flamenco will restart.</p>
<button @click="confirmWizard" :disabled="isConfirming">Confirm</button>
</section>
</div> </div>
<footer class="app-footer"> <footer class="app-footer">
@ -138,6 +97,8 @@
<script> <script>
import NotificationBar from '@/components/footer/NotificationBar.vue' import NotificationBar from '@/components/footer/NotificationBar.vue'
import UpdateListener from '@/components/UpdateListener.vue' import UpdateListener from '@/components/UpdateListener.vue'
import StepItem from '@/components/steps/StepItem.vue';
import StepsWrapper from '@/components/steps/StepsWrapper.vue';
import { MetaApi, PathCheckInput, WizardConfig } from "@/manager-api"; import { MetaApi, PathCheckInput, WizardConfig } from "@/manager-api";
import { apiClient } from '@/stores/api-query-count'; import { apiClient } from '@/stores/api-query-count';
@ -146,6 +107,8 @@ export default {
components: { components: {
NotificationBar, NotificationBar,
UpdateListener, UpdateListener,
StepsWrapper,
StepItem,
}, },
data: () => ({ data: () => ({
sharedStoragePath: "", sharedStoragePath: "",
@ -291,12 +254,7 @@ export default {
} }
</script> </script>
<style> <style>
:root {
--wiz-progress-indicator-size: 6px;
--wiz-progress-indicator-border-width: 2px;
--wiz-progress-indicator-color: var(--color-text-hint);
--wiz-progress-indicator-color-active: var(--color-accent);
}
body.is-first-time-wizard #app { body.is-first-time-wizard #app {
grid-template-areas: grid-template-areas:
@ -322,68 +280,7 @@ body.is-first-time-wizard #app {
--color-check-ok: var(--color-status-completed); --color-check-ok: var(--color-status-completed);
max-width: 640px; max-width: 640px;
margin: auto; margin: 20vh auto auto;
width: 100%;
}
.setup-step {
background-color: var(--color-background-column);
border-radius: var(--border-radius);
display: none;
padding: var(--spacer) var(--spacer-lg);
}
.setup-step.is-active{
display: block;
}
.step-intro {
text-align: center;
}
.progress {
display: flex;
justify-content: space-between;
list-style: none;
margin-bottom: 2rem;
padding: 0;
position: relative;
}
/* Progress indicator dot. */
.progress li span {
background-color: var(--wiz-progress-indicator-color);
border-radius: 50%;
border: var(--wiz-progress-indicator-border-width) solid var(--color-background-column);
box-shadow: 0 0 0 var(--wiz-progress-indicator-border-width) var(--wiz-progress-indicator-color);
content: '';
display: block;
height: var(--wiz-progress-indicator-size);
position: relative;
width: var(--wiz-progress-indicator-size);
}
.progress li.active span {
background-color: var(--color-accent);
box-shadow: 0 0 0 var(--wiz-progress-indicator-border-width) var(--wiz-progress-indicator-color-active);
}
.progress li.active+li span,
.progress li.active+li+li span,
.progress li.active+li+li+li span,
.progress li.active+li+li+li+span {
background-color: var(--color-background-column);
}
/* Progress indicator line between dots. */
.progress:before {
background-color: var(--wiz-progress-indicator-color);
content: '';
display: block;
height: var(--wiz-progress-indicator-border-width);
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%; width: 100%;
} }