✨ Implement timetable editing
This commit is contained in:
@@ -1,8 +1,25 @@
|
||||
<script setup>
|
||||
import { getSubstitutionColor } from "@/util";
|
||||
import { times } from "@/store";
|
||||
import { ref } from "vue";
|
||||
import { TrashIcon } from "lucide-vue-next";
|
||||
|
||||
defineProps(["lesson", "index"]);
|
||||
const props = defineProps(["lesson", "index", "edit", "buttons"]);
|
||||
const emit = defineEmits(["change", "delete"]);
|
||||
|
||||
const subjectElement = ref();
|
||||
const teacherElement = ref();
|
||||
const roomElement = ref();
|
||||
const lessonLength = ref(props.lesson.length || 1);
|
||||
|
||||
function update() {
|
||||
emit("change", {
|
||||
subject: subjectElement.value.innerText,
|
||||
teacher: teacherElement.value.innerText,
|
||||
room: roomElement.value.innerText,
|
||||
length: lessonLength.value,
|
||||
});
|
||||
}
|
||||
|
||||
function isChanged(lesson, key) {
|
||||
const substitution = lesson.substitution;
|
||||
@@ -43,13 +60,21 @@ function getTime(index) {
|
||||
<div class="infos">
|
||||
<!-- Subject changed -->
|
||||
<span class="subject" v-if="isChanged(lesson, 'subject')">
|
||||
<s>{{ lesson.subject }}</s> {{ lesson.substitution.change.subject }}
|
||||
<s>{{ lesson.subject }}</s>
|
||||
{{ lesson.substitution.change.subject }}
|
||||
</span>
|
||||
<!-- Cancellation -->
|
||||
<span class="subject" v-else-if="isCancelled(lesson.substitution)">
|
||||
<s>{{ lesson.subject }}</s>
|
||||
</span>
|
||||
<span class="subject" v-else>
|
||||
<span
|
||||
class="subject"
|
||||
v-else
|
||||
:contenteditable="edit"
|
||||
data-ph="Subject"
|
||||
ref="subjectElement"
|
||||
@input="update"
|
||||
>
|
||||
{{ lesson.subject }}
|
||||
</span>
|
||||
<div class="info">
|
||||
@@ -58,22 +83,43 @@ function getTime(index) {
|
||||
<s>{{ lesson.teacher }}</s>
|
||||
{{ lesson.substitution.change.teacher }}</span
|
||||
>
|
||||
<span class="info" v-else> {{ lesson.teacher }}</span>
|
||||
<span
|
||||
class="info"
|
||||
v-else
|
||||
:contenteditable="edit"
|
||||
data-ph="Teacher"
|
||||
ref="teacherElement"
|
||||
@input="update"
|
||||
>
|
||||
{{ lesson.teacher }}</span
|
||||
>
|
||||
<!-- Room changed -->
|
||||
<span class="info" v-if="isChanged(lesson, 'room')"
|
||||
>, <s>{{ lesson.room }}</s> {{ lesson.substitution.change.room }}
|
||||
</span>
|
||||
<span class="info" v-else-if="lesson.room">, {{ lesson.room }}</span>
|
||||
<span class="info" v-else-if="lesson.room || edit"
|
||||
>,
|
||||
<span
|
||||
:contenteditable="edit"
|
||||
data-ph="Room"
|
||||
ref="roomElement"
|
||||
@input="update"
|
||||
>{{ lesson.room }}</span
|
||||
></span
|
||||
>
|
||||
<!-- Show notes if available -->
|
||||
<span class="info" v-if="getNotes(lesson.substitution)"
|
||||
>, {{ $t("timetable.notes") }} {{ getNotes(lesson.substitution) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="times" v-if="getTime(index).start">
|
||||
<div class="times" v-if="getTime(index).start && !edit">
|
||||
<span>{{ getTime(index).start }} -</span>
|
||||
<span>{{ getTime(index).end }}</span>
|
||||
</div>
|
||||
<div class="buttons" v-if="edit && buttons">
|
||||
<TrashIcon @click="$emit('delete')" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -119,4 +165,19 @@ function getTime(index) {
|
||||
opacity: 0.5;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
margin-left: auto;
|
||||
opacity: 0.7;
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
[contenteditable="true"]:empty:before {
|
||||
content: attr(data-ph);
|
||||
opacity: 0.4;
|
||||
cursor: text;
|
||||
}
|
||||
</style>
|
||||
|
||||
100
src/components/lesson-group-list.vue
Normal file
100
src/components/lesson-group-list.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<script setup>
|
||||
import { toRaw, ref } from "vue";
|
||||
import LessonCard from "@/components/lesson-card.vue";
|
||||
import {
|
||||
ArrowUpIcon,
|
||||
ArrowDownIcon,
|
||||
SettingsIcon,
|
||||
TrashIcon,
|
||||
PlusIcon,
|
||||
} from "lucide-vue-next";
|
||||
|
||||
const props = defineProps(["lesson", "index", "edit"]);
|
||||
const emit = defineEmits(["change", "move"]);
|
||||
|
||||
const advancedOptions = ref(false);
|
||||
|
||||
const lessonLength = ref(1);
|
||||
function updateLength() {
|
||||
let newLesson = structuredClone(toRaw(props.lesson));
|
||||
for (let entry of newLesson) {
|
||||
entry.length = lessonLength.value;
|
||||
}
|
||||
emit("change", newLesson);
|
||||
}
|
||||
|
||||
function appendOption() {
|
||||
let newLesson = structuredClone(toRaw(props.lesson));
|
||||
if (Array.isArray(newLesson)) newLesson.push({});
|
||||
else newLesson = [newLesson, {}];
|
||||
emit("change", newLesson);
|
||||
}
|
||||
|
||||
function lessonChanged(index, data) {
|
||||
let newLesson = structuredClone(toRaw(props.lesson));
|
||||
newLesson[index] = data;
|
||||
if (newLesson.length > 1)
|
||||
newLesson[index].group = `${data.subject}: ${data.teacher}`;
|
||||
else delete newLesson[index].group;
|
||||
emit("change", newLesson);
|
||||
}
|
||||
|
||||
function lessonDeleted(index) {
|
||||
let newLesson = structuredClone(toRaw(props.lesson));
|
||||
newLesson.splice(index, 1);
|
||||
if (newLesson.length == 0) emit("delete");
|
||||
else emit("change", newLesson);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="lessonList">
|
||||
<div class="buttons" v-if="edit">
|
||||
<ArrowUpIcon @click="$emit('move', 'up')" />
|
||||
<ArrowDownIcon @click="$emit('move', 'down')" />
|
||||
<SettingsIcon @click="advancedOptions = !advancedOptions" />
|
||||
<TrashIcon @click="$emit('delete')" />
|
||||
<PlusIcon @click="appendOption" />
|
||||
</div>
|
||||
<LessonCard
|
||||
v-for="(option, groupIndex) in lesson"
|
||||
:key="groupIndex"
|
||||
:lesson="option"
|
||||
:index="index"
|
||||
:edit="edit"
|
||||
:buttons="edit"
|
||||
@change="(data) => lessonChanged(groupIndex, data)"
|
||||
@delete="() => lessonDeleted(groupIndex)"
|
||||
/>
|
||||
<div class="advanced" v-show="advancedOptions" v-if="edit">
|
||||
<span>Length: </span>
|
||||
<input
|
||||
type="number"
|
||||
v-model="lessonLength"
|
||||
@change="updateLength"
|
||||
min="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.lessonList {
|
||||
border-left: 2px solid var(--text-color);
|
||||
padding-left: 5px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
opacity: 0.7;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 30px;
|
||||
}
|
||||
</style>
|
||||
44
src/components/settings/editor-navbar.vue
Normal file
44
src/components/settings/editor-navbar.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<script setup>
|
||||
import { BanIcon, SaveIcon } from "lucide-vue-next";
|
||||
|
||||
defineEmits(["abort", "save"]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bottomnav">
|
||||
<div class="entry danger" @click="$emit('back')">
|
||||
<BanIcon />
|
||||
<span>Abort</span>
|
||||
</div>
|
||||
<div class="entry success" @click="$emit('save')">
|
||||
<SaveIcon />
|
||||
<span>Save</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.bottomnav {
|
||||
width: calc(90% - 40px);
|
||||
height: 50px;
|
||||
max-width: 800px;
|
||||
padding: 0px 20px;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
display: grid;
|
||||
grid-auto-columns: 1fr;
|
||||
grid-auto-flow: column;
|
||||
z-index: 100;
|
||||
border-radius: 10px;
|
||||
background-color: var(--bottomnav-color);
|
||||
box-shadow: var(--bottomnav-shadow);
|
||||
}
|
||||
|
||||
.entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -42,7 +42,7 @@ const linkedTimetable = computed(() => {
|
||||
</div>
|
||||
<div class="listContainer">
|
||||
<template v-for="(lesson, index) in linkedTimetable" :key="index">
|
||||
<LessonCard :lesson="lesson" :index="index" />
|
||||
<LessonCard :lesson="lesson" :index="index" :edit="false" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user