commit 77
This commit is contained in:
parent
18dc17d6d5
commit
9a8dcabdd6
22 changed files with 258 additions and 149 deletions
|
@ -14,7 +14,7 @@ fun SceneBuilderContext.songMittsommernacht() {
|
||||||
step(StepCue.MusicStart("Mittsommernacht", 4.minutes + 30.seconds)) {
|
step(StepCue.MusicStart("Mittsommernacht", 4.minutes + 30.seconds)) {
|
||||||
actors {
|
actors {
|
||||||
// TODO: Expand
|
// TODO: Expand
|
||||||
+"Einwohner von Huntington / von links & durch Mitte"
|
+"Einwohner / von links & durch Mitte"
|
||||||
}
|
}
|
||||||
|
|
||||||
curtainState = CurtainState.OPEN
|
curtainState = CurtainState.OPEN
|
||||||
|
@ -281,7 +281,7 @@ fun SceneBuilderContext.songMittsommernacht() {
|
||||||
|
|
||||||
step(StepCue.MusicEnd) {
|
step(StepCue.MusicEnd) {
|
||||||
actors {
|
actors {
|
||||||
-"Einwohner von Huntington"
|
-"Einwohner"
|
||||||
+"Mina / durch Mitte, mit Koffer & Taschentuch"
|
+"Mina / durch Mitte, mit Koffer & Taschentuch"
|
||||||
+"Lucy / durch Mitte"
|
+"Lucy / durch Mitte"
|
||||||
+"Jonathan / von links"
|
+"Jonathan / von links"
|
||||||
|
|
|
@ -6,6 +6,7 @@ import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableMap
|
import kotlinx.collections.immutable.toImmutableMap
|
||||||
import kotlinx.collections.immutable.toImmutableSet
|
import kotlinx.collections.immutable.toImmutableSet
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
@DslMarker
|
@DslMarker
|
||||||
annotation class TheaterDslMarker
|
annotation class TheaterDslMarker
|
||||||
|
@ -103,8 +104,8 @@ private fun buildAct(actIndex: Int, actName: String, build: ActBuilderContext.()
|
||||||
|
|
||||||
override fun step(cue: StepCue, build: StepDataBuilderContext.() -> Unit) {
|
override fun step(cue: StepCue, build: StepDataBuilderContext.() -> Unit) {
|
||||||
val changedProps = mutableMapOf<PropPosition, StringWithDetails?>()
|
val changedProps = mutableMapOf<PropPosition, StringWithDetails?>()
|
||||||
val actorEntrances = mutableSetOf<StringWithDetails>()
|
val actorEntrances = TreeSet<StringWithDetails>()
|
||||||
val actorExits = mutableSetOf<StringWithDetails>()
|
val actorExits = TreeSet<StringWithDetails>()
|
||||||
var runner: StepRunner? = null
|
var runner: StepRunner? = null
|
||||||
|
|
||||||
object : StepDataBuilderContext {
|
object : StepDataBuilderContext {
|
||||||
|
@ -168,6 +169,7 @@ private fun buildAct(actIndex: Int, actName: String, build: ActBuilderContext.()
|
||||||
|
|
||||||
actorsOnStage.removeAll(actorExitsNames.toSet())
|
actorsOnStage.removeAll(actorExitsNames.toSet())
|
||||||
actorsOnStage.addAll(actorEntrancesNames)
|
actorsOnStage.addAll(actorEntrancesNames)
|
||||||
|
actorsOnStage.sort()
|
||||||
|
|
||||||
changedProps.forEach { (k, v) -> props[k] = v }
|
changedProps.forEach { (k, v) -> props[k] = v }
|
||||||
|
|
||||||
|
|
|
@ -37,24 +37,9 @@ sealed interface StepCue {
|
||||||
override fun format() = "curtain: $state${if (whileMoving) "(while moving)" else ""}"
|
override fun format() = "curtain: $state${if (whileMoving) "(while moving)" else ""}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("LIGHT")
|
|
||||||
data class Light(val state: State, val whileFading: Boolean) : StepCue {
|
|
||||||
enum class State {
|
|
||||||
@SerialName("on")
|
|
||||||
ON,
|
|
||||||
|
|
||||||
@SerialName("off")
|
|
||||||
OFF
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun format() = "light: $state${if (whileFading) "(while fading)" else ""}"
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("CUSTOM")
|
@SerialName("CUSTOM")
|
||||||
data class Custom(val text: String) : StepCue {
|
data class Custom(val text: String) : StepCue {
|
||||||
override fun format() = "custom: $text"
|
override fun format() = "custom: $text"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@ import kotlinx.serialization.Serializable
|
||||||
*/
|
*/
|
||||||
@JvmInline
|
@JvmInline
|
||||||
@Serializable
|
@Serializable
|
||||||
value class StringWithDetails(val value: String) {
|
value class StringWithDetails(val value: String) : Comparable<StringWithDetails> {
|
||||||
companion object {
|
companion object {
|
||||||
const val DELIMITER = " / "
|
const val DELIMITER = " / "
|
||||||
}
|
}
|
||||||
|
@ -15,4 +15,6 @@ value class StringWithDetails(val value: String) {
|
||||||
val main get() = value.split(DELIMITER)[0]
|
val main get() = value.split(DELIMITER)[0]
|
||||||
val details: String? get() = value.split(DELIMITER, limit = 2).takeIf { it.size == 2 }?.let { it[1] }
|
val details: String? get() = value.split(DELIMITER, limit = 2).takeIf { it.size == 2 }?.let { it[1] }
|
||||||
val hasDetails get() = details !== null
|
val hasDetails get() = details !== null
|
||||||
|
|
||||||
|
override fun compareTo(other: StringWithDetails): Int = value.compareTo(other.value)
|
||||||
}
|
}
|
|
@ -4,10 +4,10 @@
|
||||||
<div class="text-s1">Janus, created by Moritz Ruth</div>
|
<div class="text-s1">Janus, created by Moritz Ruth</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="h-100dvh flex flex-col">
|
<div v-else class="h-100dvh flex flex-col">
|
||||||
<div class="font-black text-2xl md:text-4xl p-4 md:p-8 pb-0 md:pb-0 flex-shrink-0">
|
<div class="font-black text-2xl md:text-4xl px-4 pt-4 flex-shrink-0 truncate">
|
||||||
{{ current.act === null ? "" : `${current.act.name} — ` }}{{ current.scene.name }}
|
{{ current.act === null ? "" : `${current.act.name} — ` }}{{ current.scene.name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow p-4 md:p-8 overflow-hidden">
|
<div class="flex-grow p-4 overflow-hidden">
|
||||||
<router-view/>
|
<router-view/>
|
||||||
</div>
|
</div>
|
||||||
<MusicProgressBar class="h-10 flex-shrink-0"/>
|
<MusicProgressBar class="h-10 flex-shrink-0"/>
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="overflow-y-auto">
|
<transition-group name="list" tag="div" class="overflow-y-auto md:columns-200px">
|
||||||
<transition-group name="list" tag="div">
|
<div v-if="current.step.actorsOnStage.length === 0" key="" class="text-gray-400">Niemand</div>
|
||||||
<div v-if="current.step.actorsOnStage.length === 0" key="" class="text-gray-400">Niemand</div>
|
<div
|
||||||
<div
|
v-for="actor in current.step.actorsOnStage"
|
||||||
v-for="actor in current.step.actorsOnStage"
|
:key="parseStringWithDetails(actor).main"
|
||||||
:key="parseStringWithDetails(actor).main"
|
class="truncate line-height-normal"
|
||||||
class="truncate text-4.5"
|
>
|
||||||
>
|
{{ actor }}
|
||||||
{{ actor }}
|
</div>
|
||||||
</div>
|
</transition-group>
|
||||||
</transition-group>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div :data-blinking="isBlinking" class="overflow-hidden text-6 box p-4">
|
<div :data-blinking="isBlinking" class="overflow-hidden text-6 py-2" :class="$style.root">
|
||||||
{{ message }}
|
<div v-if="message.trim().length === 0" class="text-gray-400">
|
||||||
|
Keine Nachricht vorhanden.
|
||||||
|
</div>
|
||||||
|
<template v-else>{{ message }}</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style module>
|
||||||
.box {
|
.root {
|
||||||
&[data-blinking="true"] {
|
&[data-blinking="true"] {
|
||||||
animation: alternate infinite 500ms ease-in-out pulse;
|
animation: alternate infinite 500ms ease-in-out pulse;
|
||||||
}
|
}
|
||||||
|
@ -22,25 +25,15 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script setup lang="ts">
|
||||||
import { state } from "../state"
|
import { state } from "@/state"
|
||||||
import { toRef, watch } from "vue"
|
import { toRef, watch } from "vue"
|
||||||
import { autoResetRef } from "@vueuse/core"
|
import { autoResetRef } from "@vueuse/core"
|
||||||
|
|
||||||
export default {
|
const message = toRef(state, "message")
|
||||||
name: "MessageDisplay",
|
const isBlinking = autoResetRef(false, 10 * 1000)
|
||||||
setup() {
|
|
||||||
const message = toRef(state, "message")
|
|
||||||
const isBlinking = autoResetRef(false, 10 * 1000)
|
|
||||||
|
|
||||||
watch(message, () => {
|
watch(message, () => {
|
||||||
isBlinking.value = message.value !== ""
|
isBlinking.value = message.value !== ""
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
|
||||||
message,
|
|
||||||
isBlinking
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="scrollable ? 'overflow-y-auto' : 'overflow-hidden'" class="flex flex-col space-y-5">
|
<div :class="scrollable ? 'overflow-y-auto' : 'overflow-hidden'" class="flex flex-col gap-5">
|
||||||
<div v-for="(act, actIndex) in show.acts">
|
<div v-for="(act, index) in show.acts" :key="index">
|
||||||
<MotionsListAct :act="act" :center-current="Boolean(centerCurrent)"/>
|
<MotionsListAct :act="act" :center-current="Boolean(centerCurrent)"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-[50%] flex-shrink-0"/>
|
<div class="h-[50%] flex-shrink-0"/>
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import MotionsListAct from "./MotionsListAct.vue"
|
import MotionsListAct from "./MotionsListAct.vue"
|
||||||
import { show } from "../state"
|
import { show } from "@/state"
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
centerCurrent?: boolean
|
centerCurrent?: boolean
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="pt-2">
|
<div class="pt-2">
|
||||||
<div class="font-bold text-7 flex gap-5 items-center pb-4">
|
<div class="font-bold text-7 flex gap-7 items-center pb-4">
|
||||||
<span class="flex-grow h-2px bg-white"></span>
|
<span class="flex-grow h-2px bg-gray-300"></span>
|
||||||
<span>{{ act.name }}</span>
|
<span>{{ act.name }}</span>
|
||||||
<span class="flex-grow h-2px bg-white"></span>
|
<span class="flex-grow h-2px bg-gray-300"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-6">
|
||||||
<div
|
<div
|
||||||
v-for="(scene, sceneIndex) in scenes"
|
v-for="(scene, sceneIndex) in scenes"
|
||||||
:key="sceneIndex"
|
:key="sceneIndex"
|
||||||
>
|
>
|
||||||
<div class="text-gray-400 pl-3 text-5">
|
<div class="text-gray-400 pl-3 text-5 pb-1">
|
||||||
{{ scene.name }}
|
{{ scene.name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Act, Scene, ShowPosition, Step } from "../state"
|
import { Act, Scene, ShowPosition, Step } from "@/state"
|
||||||
import { computed } from "vue"
|
import { computed } from "vue"
|
||||||
import MotionsListStep from "./MotionsListStep.vue"
|
import MotionsListStep from "./MotionsListStep.vue"
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="isActive && 'bg-green-800'" class="transition p-3">
|
<div :class="isActive && 'bg-green-800'" class="transition p-3 rounded-2xl">
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
<div class="flex-grow">
|
<div class="flex-grow">
|
||||||
<CueBox :step="step" text-class="text-6"/>
|
<CueBox class="flex-shrink-0" text-class="text-6" :step="step"/>
|
||||||
<div v-if="step.actorEntrances.length + step.actorExits.length > 0" class="py-2 pl-8 space-y-2 text-7">
|
<div v-if="step.actorEntrances.length + step.actorExits.length > 0" class="py-2 pl-8 space-y-2 text-7">
|
||||||
<div class="flex flex-col space-y-1">
|
<div class="flex flex-col space-y-1">
|
||||||
<div
|
<div
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { parseStringWithDetails, ShowPosition, START_STEP, state, Step } from "../state"
|
import { parseStringWithDetails, ShowPosition, START_STEP, state, Step } from "@/state"
|
||||||
import CueBox from "./CueBox.vue"
|
import CueBox from "./CueBox.vue"
|
||||||
import CaretDoubleRightIcon from "virtual:icons/ph/caret-double-right"
|
import CaretDoubleRightIcon from "virtual:icons/ph/caret-double-right"
|
||||||
import CaretDoubleLeftIcon from "virtual:icons/ph/caret-double-left"
|
import CaretDoubleLeftIcon from "virtual:icons/ph/caret-double-left"
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const position = toRef(state, "position")
|
const position = toRef(state, "position")
|
||||||
const element = useCurrentElement()
|
const element = useCurrentElement<HTMLElement>()
|
||||||
const allPositions = computed(() => [props.step.position, ...(props.morePositions ?? [])])
|
const allPositions = computed(() => [props.step.position, ...(props.morePositions ?? [])])
|
||||||
const isActive = computed(() => allPositions.value.some(p => isEqual(p, position.value)))
|
const isActive = computed(() => allPositions.value.some(p => isEqual(p, position.value)))
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<ChangeBlinkingBox :blink-seconds="20" :value="prop" class="items-center">
|
<ChangeBlinkingBox :blink-seconds="20" :value="prop" class="flex flex-col items-center">
|
||||||
<div class="text-s1 tracking-wide text-gray-500">
|
<div class="text-s1 tracking-wide text-gray-400">
|
||||||
{{ positionName }}
|
{{ positionName }}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow w-full">
|
<div class="flex-grow w-full">
|
||||||
<transition mode="out-in" name="fade">
|
<transition mode="out-in" name="fade">
|
||||||
<div :key="prop" class="flex flex-col items-center justify-center">
|
<div :key="prop ?? ''" class="flex flex-col items-center justify-center">
|
||||||
<template v-if="prop !== null">
|
<div v-if="prop !== null" class="font-bold text-5 text-center">
|
||||||
<div class="font-bold text-3 text-center">
|
{{ prop }}
|
||||||
{{ parseStringWithDetails(prop).main }}
|
</div>
|
||||||
</div>
|
|
||||||
<div v-if="parseStringWithDetails(prop).details" class="text-center px-2">
|
|
||||||
{{ parseStringWithDetails(prop).details }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,10 +27,9 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import { toRef, watch } from "vue"
|
import { toRef, watch } from "vue"
|
||||||
import { autoResetRef } from "@vueuse/core"
|
import { autoResetRef } from "@vueuse/core"
|
||||||
import { parseStringWithDetails } from "../state"
|
|
||||||
import ChangeBlinkingBox from "./ChangeBlinkingBox.vue"
|
import ChangeBlinkingBox from "./ChangeBlinkingBox.vue"
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
|
@ -5,17 +5,17 @@
|
||||||
Publikum
|
Publikum
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.row" class="border-t border-b border-dark-300 h-30">
|
<div :class="$style.row" class="border-t border-b border-dark-300 h-20">
|
||||||
<PropBox :prop="current.step.props.PROSCENIUM_RIGHT" position-name="Rechte Vorbühne"/>
|
<PropBox :prop="current.step.props.PROSCENIUM_RIGHT" position-name="Rechte Vorbühne"/>
|
||||||
<PropBox :prop="current.step.props.PROSCENIUM_CENTER" position-name="Mitte der Vorbühne"/>
|
<PropBox :prop="current.step.props.PROSCENIUM_CENTER" position-name="Mitte der Vorbühne"/>
|
||||||
<PropBox :prop="current.step.props.PROSCENIUM_LEFT" position-name="Linke der Vorbühne"/>
|
<PropBox :prop="current.step.props.PROSCENIUM_LEFT" position-name="Linke der Vorbühne"/>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.row" class="flex-grow h-0">
|
<div :class="$style.row" class="flex-grow h-20">
|
||||||
<PropBox :prop="current.step.props.RIGHT" position-name="Rechts"/>
|
<PropBox :prop="current.step.props.RIGHT" position-name="Rechts"/>
|
||||||
<PropBox :prop="current.step.props.CENTER" position-name="Mitte"/>
|
<PropBox :prop="current.step.props.CENTER" position-name="Mitte"/>
|
||||||
<PropBox :prop="current.step.props.LEFT" position-name="Links"/>
|
<PropBox :prop="current.step.props.LEFT" position-name="Links"/>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.row" class="border-t border-dark-300 py-3 h-20">
|
<div :class="$style.row" class="border-t border-dark-300 h-11">
|
||||||
<div/>
|
<div/>
|
||||||
<PropBox :prop="current.step.props.BACKDROP" position-name="Rückwand"/>
|
<PropBox :prop="current.step.props.BACKDROP" position-name="Rückwand"/>
|
||||||
<div/>
|
<div/>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import { current } from "../state"
|
import { current } from "@/state"
|
||||||
import PropBox from "./PropBox.vue"
|
import PropBox from "./PropBox.vue"
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="absolute right-3 top-2 text-5 pointer-events-none flex items-center gap-1">
|
<div class="absolute right-3 top-2 text-5 pointer-events-none flex items-center gap-1 <md:hidden">
|
||||||
<ClockIcon/>
|
<ClockIcon/>
|
||||||
<span class="font-bold tabular-nums tracking-tighter">{{ format.format(syncedTime) }}</span>
|
<span class="font-bold tabular-nums tracking-tighter">{{ format.format(syncedTime) }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { syncedTime } from "../syncing"
|
import { syncedTime } from "@/syncing"
|
||||||
import ClockIcon from "virtual:icons/ph/clock-bold"
|
import ClockIcon from "virtual:icons/ph/clock-bold"
|
||||||
|
|
||||||
const format = new Intl.DateTimeFormat("de", {
|
const format = new Intl.DateTimeFormat("de", {
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex flex-col h-full">
|
|
||||||
<h1 class="font-800 text-9 p-4 pb-0">
|
|
||||||
{{ current.act === null ? "" : `${current.act.name} — ` }}{{ current.scene.name }}
|
|
||||||
</h1>
|
|
||||||
<div class="h-full flex space-x-4 p-4 pt-8 flex-grow overflow-hidden">
|
|
||||||
<MotionsList center-current class="w-3/7" scrollable/>
|
|
||||||
<div class="w-4/7 flex flex-col space-y-4">
|
|
||||||
<ActorsOnStageBox class="h-full text-7"/>
|
|
||||||
<MessageEdit class="h-40"/>
|
|
||||||
<CurtainLightControl/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<MusicProgressBar class="h-10"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import MusicProgressBar from "../../components/MusicProgressBar.vue"
|
|
||||||
import MotionsList from "../../components/MotionsList.vue"
|
|
||||||
import { current } from "../../state"
|
|
||||||
import ActorsOnStageBox from "../../components/ActorsOnStageBox.vue"
|
|
||||||
import MessageEdit from "../../components/MessageEdit.vue"
|
|
||||||
import CurtainLightControl from "../../components/CurtainLightControl.vue"
|
|
||||||
</script>
|
|
75
ui/src/pages/for/fly-crew.vue
Normal file
75
ui/src/pages/for/fly-crew.vue
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col gap-50">
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<div class="text-gray text-2xl">
|
||||||
|
Aktuelle Anweisung
|
||||||
|
</div>
|
||||||
|
<ChangeBlinkingBox :blink-seconds="10" :value="currentState" class="text-7 md:text-10">
|
||||||
|
{{ getDisplayedCommand(currentState) }}
|
||||||
|
</ChangeBlinkingBox>
|
||||||
|
</div>
|
||||||
|
<div v-if="nextStepWithChange !== null" class="flex flex-col gap-2">
|
||||||
|
<div class="text-gray text-6">
|
||||||
|
Nächste Anweisung
|
||||||
|
<span class="whitespace-nowrap">
|
||||||
|
[{{
|
||||||
|
nextStepWithChange.delta === 0
|
||||||
|
? "in dieser Szene"
|
||||||
|
: nextStepWithChange.delta === 1
|
||||||
|
? "in der nächsten Szene"
|
||||||
|
: `in ${nextStepWithChange.delta} Szenen`
|
||||||
|
}}]
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-7 md:text-10">{{ getDisplayedCommand(nextStepWithChange.state) }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style module>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from "vue"
|
||||||
|
import { current, CurtainState, getNextValidPosition, getSceneIndex, getStep, ShowPosition } from "@/state"
|
||||||
|
import ChangeBlinkingBox from "@/components/ChangeBlinkingBox.vue"
|
||||||
|
|
||||||
|
const currentState = computed(() => current.step.curtainState)
|
||||||
|
|
||||||
|
interface StepWithChange {
|
||||||
|
delta: number
|
||||||
|
position: ShowPosition
|
||||||
|
state: CurtainState
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDisplayedCommand(value: CurtainState) {
|
||||||
|
if (value === "open") {
|
||||||
|
return "Öffnen"
|
||||||
|
} else {
|
||||||
|
return "Schließen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextStepWithChange = computed<StepWithChange | null>(() => {
|
||||||
|
let position: ShowPosition | null = getNextValidPosition(current.step.position)
|
||||||
|
let lastState: CurtainState = currentState.value
|
||||||
|
|
||||||
|
while (position !== null) {
|
||||||
|
const step = getStep(position)
|
||||||
|
|
||||||
|
if (step.curtainState !== lastState) {
|
||||||
|
return {
|
||||||
|
position: step.position,
|
||||||
|
delta: getSceneIndex(step.position) - current.sceneIndex,
|
||||||
|
state: step.curtainState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastState = step.curtainState
|
||||||
|
position = getNextValidPosition(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
</script>
|
36
ui/src/pages/for/sound-operator.vue
Executable file
36
ui/src/pages/for/sound-operator.vue
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
<template>
|
||||||
|
<div class="grid grid-cols-2 gap-6 h-full">
|
||||||
|
<MotionsList center-current scrollable/>
|
||||||
|
<div class="flex flex-col gap-5 overflow-y-auto">
|
||||||
|
<div>
|
||||||
|
<div class="pb-2 font-bold text-3.5 tracking-wider uppercase">
|
||||||
|
Vorhang
|
||||||
|
</div>
|
||||||
|
<div class="text-4.5">
|
||||||
|
{{ current.step.curtainState === "open" ? "öffnen" : "schließen" }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow overflow-y-hidden flex flex-col">
|
||||||
|
<div class="pb-2 font-bold text-3.5 tracking-wider uppercase">
|
||||||
|
Auf der Bühne
|
||||||
|
</div>
|
||||||
|
<ActorsOnStageBox class="flex-grow text-8"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="pb-2 font-bold text-3.5 tracking-wider uppercase">
|
||||||
|
Umbaulicht
|
||||||
|
</div>
|
||||||
|
<CurtainLightControl/>
|
||||||
|
</div>
|
||||||
|
<MessageEdit class="h-25 md:h-40 mb-1"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import MotionsList from "../../components/MotionsList.vue"
|
||||||
|
import ActorsOnStageBox from "../../components/ActorsOnStageBox.vue"
|
||||||
|
import MessageEdit from "../../components/MessageEdit.vue"
|
||||||
|
import CurtainLightControl from "../../components/CurtainLightControl.vue"
|
||||||
|
import { current } from "@/state"
|
||||||
|
</script>
|
33
ui/src/pages/for/stage.vue
Executable file
33
ui/src/pages/for/stage.vue
Executable file
|
@ -0,0 +1,33 @@
|
||||||
|
<template>
|
||||||
|
<div class="grid grid-cols-2 gap-6 h-full" :class="$style.root">
|
||||||
|
<MotionsList center-current scrollable/>
|
||||||
|
<div class="flex flex-col gap-5 overflow-y-hidden">
|
||||||
|
<StageTopDownView/>
|
||||||
|
<div class="flex-grow overflow-hidden">
|
||||||
|
<div class="pb-2 font-bold text-6 tracking-wider uppercase">
|
||||||
|
Auf der Bühne
|
||||||
|
</div>
|
||||||
|
<ActorsOnStageBox class="flex-grow h-full text-7"/>
|
||||||
|
</div>
|
||||||
|
<div class="h-35">
|
||||||
|
<div class="font-bold text-6 tracking-wider uppercase">
|
||||||
|
Nachricht
|
||||||
|
</div>
|
||||||
|
<MessageDisplay/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style module lang="scss">
|
||||||
|
.root {
|
||||||
|
grid-template-columns: 2fr 3fr;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import MotionsList from "@/components/MotionsList.vue"
|
||||||
|
import ActorsOnStageBox from "@/components/ActorsOnStageBox.vue"
|
||||||
|
import MessageDisplay from "@/components/MessageDisplay.vue"
|
||||||
|
import StageTopDownView from "@/components/StageTopDownView.vue"
|
||||||
|
</script>
|
|
@ -2,8 +2,7 @@
|
||||||
<div class="grid md:grid-cols-2 gap-6 h-full" :class="$style.root">
|
<div class="grid md:grid-cols-2 gap-6 h-full" :class="$style.root">
|
||||||
<StepSelection/>
|
<StepSelection/>
|
||||||
<div class="flex flex-col gap-5 overflow-y-auto">
|
<div class="flex flex-col gap-5 overflow-y-auto">
|
||||||
<MessageEdit class="h-25 md:h-40"/>
|
<div>
|
||||||
<div class="text-5">
|
|
||||||
<div class="pb-2 font-bold text-3.5 tracking-wider uppercase">
|
<div class="pb-2 font-bold text-3.5 tracking-wider uppercase">
|
||||||
Vorhang
|
Vorhang
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,11 +10,11 @@
|
||||||
{{ current.step.curtainState === "open" ? "öffnen" : "schließen" }}
|
{{ current.step.curtainState === "open" ? "öffnen" : "schließen" }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow overflow-hidden">
|
<div class="flex-grow overflow-y-hidden flex flex-col">
|
||||||
<div class="pb-2 font-bold text-3.5 tracking-wider uppercase">
|
<div class="pb-2 font-bold text-3.5 tracking-wider uppercase">
|
||||||
Auf der Bühne
|
Auf der Bühne
|
||||||
</div>
|
</div>
|
||||||
<ActorsOnStageBox class="flex-grow h-full"/>
|
<ActorsOnStageBox class="flex-grow text-4.5"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="pb-2 font-bold text-3.5 tracking-wider uppercase">
|
<div class="pb-2 font-bold text-3.5 tracking-wider uppercase">
|
||||||
|
@ -29,6 +28,7 @@
|
||||||
</div>
|
</div>
|
||||||
<CurtainLightControl/>
|
<CurtainLightControl/>
|
||||||
</div>
|
</div>
|
||||||
|
<MessageEdit class="h-25 md:h-40 mb-1"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
|
@ -1,6 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-4 text-xl">
|
<div class="flex flex-col items-center gap-4 text-2xl pt-20">
|
||||||
<router-link to="/mixer">audio operator</router-link>
|
<router-link
|
||||||
|
v-for="dashboard in DASHBOARDS"
|
||||||
|
:key="dashboard.to"
|
||||||
|
class="flex items-center gap-2 rounded-xl bg-gray-900 p-5 hover:bg-gray-800 transition"
|
||||||
|
:to="dashboard.to"
|
||||||
|
>
|
||||||
|
<component :is="dashboard.icon"/>
|
||||||
|
<div class="font-bold">{{ dashboard.label }}</div>
|
||||||
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -9,5 +17,38 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { type Component } from "vue"
|
||||||
|
import FlyingSaucerIcon from "virtual:icons/ph/flying-saucer"
|
||||||
|
import CircleWavyIcon from "virtual:icons/ph/circle-wavy"
|
||||||
|
import FadersIcon from "virtual:icons/ph/faders"
|
||||||
|
import StorefrontIcon from "virtual:icons/ph/storefront"
|
||||||
|
|
||||||
|
interface Dashboard {
|
||||||
|
to: string
|
||||||
|
label: string
|
||||||
|
icon: Component
|
||||||
|
}
|
||||||
|
|
||||||
|
const DASHBOARDS: Dashboard[] = [
|
||||||
|
{
|
||||||
|
to: "/for/fly-crew",
|
||||||
|
label: "Fly crew",
|
||||||
|
icon: FlyingSaucerIcon
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: "/for/followspot-operator",
|
||||||
|
label: "Followspot operator",
|
||||||
|
icon: CircleWavyIcon
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: "/for/sound-operator",
|
||||||
|
label: "Sound operator",
|
||||||
|
icon: FadersIcon
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: "/for/stage",
|
||||||
|
label: "Stage",
|
||||||
|
icon: StorefrontIcon
|
||||||
|
}
|
||||||
|
]
|
||||||
</script>
|
</script>
|
|
@ -1,23 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex flex-col h-full">
|
|
||||||
<h1 class="font-800 text-9 p-4 pb-0">
|
|
||||||
{{ current.act === null ? "" : `${current.act.name} — ` }}{{ current.scene.name }}
|
|
||||||
</h1>
|
|
||||||
<div class="h-full flex space-x-4 p-4 pt-8 flex-grow overflow-hidden">
|
|
||||||
<MotionsList center-current class="w-3/7"/>
|
|
||||||
<div class="w-4/7 flex flex-col space-y-4">
|
|
||||||
<StageTopDownView class="h-full"/>
|
|
||||||
<MessageDisplay class="h-30"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<MusicProgressBar class="h-15"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import MusicProgressBar from "../../components/MusicProgressBar.vue"
|
|
||||||
import { current } from "../../state"
|
|
||||||
import MotionsList from "../../components/MotionsList.vue"
|
|
||||||
import StageTopDownView from "../../components/StageTopDownView.vue"
|
|
||||||
import MessageDisplay from "../../components/MessageDisplay.vue"
|
|
||||||
</script>
|
|
|
@ -21,9 +21,11 @@ export interface Step {
|
||||||
hasChangedProps: boolean
|
hasChangedProps: boolean
|
||||||
leftSpotTarget: string | null
|
leftSpotTarget: string | null
|
||||||
rightSpotTarget: string | null
|
rightSpotTarget: string | null
|
||||||
curtainState: "open" | "closed"
|
curtainState: CurtainState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CurtainState = "open" | "closed"
|
||||||
|
|
||||||
export type StepCue = {
|
export type StepCue = {
|
||||||
type: "TEXT",
|
type: "TEXT",
|
||||||
speaker: string
|
speaker: string
|
||||||
|
@ -37,13 +39,9 @@ export type StepCue = {
|
||||||
type: "MUSIC_END"
|
type: "MUSIC_END"
|
||||||
} | {
|
} | {
|
||||||
type: "CURTAIN",
|
type: "CURTAIN",
|
||||||
state: "open" | "closed"
|
state: CurtainState
|
||||||
whileMoving: boolean
|
whileMoving: boolean
|
||||||
} | {
|
} | {
|
||||||
type: "LIGHTS"
|
|
||||||
state: "on" | "off"
|
|
||||||
whileFading: boolean
|
|
||||||
} | {
|
|
||||||
type: "CUSTOM"
|
type: "CUSTOM"
|
||||||
text: string
|
text: string
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue