Add Nuxt
This commit is contained in:
64
app/components/Embla.vue
Normal file
64
app/components/Embla.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<script setup>
|
||||
import emblaCarouselVue from "embla-carousel-vue";
|
||||
import RitzenbergenLib from "../ritzenbergenlib.ts";
|
||||
import { onMounted, ref } from "vue";
|
||||
import EmblaItem from "./EmblaItem.vue";
|
||||
|
||||
const emblaApi = ref();
|
||||
|
||||
const [emblaRef, emblaInstance] = emblaCarouselVue({ loop: true });
|
||||
|
||||
let timeout=false;
|
||||
|
||||
onMounted(() => {
|
||||
emblaApi.value = emblaInstance.value;
|
||||
setInterval(()=>{
|
||||
if(!timeout) emblaApi.value?.scrollNext();
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
const prev = () => {
|
||||
emblaApi.value?.scrollPrev();
|
||||
addTimeout();
|
||||
};
|
||||
|
||||
const next = () => {
|
||||
emblaApi.value?.scrollNext();
|
||||
addTimeout();
|
||||
};
|
||||
function addTimeout(){
|
||||
timeout=true;
|
||||
setTimeout(()=>{
|
||||
timeout=false;
|
||||
}, 4000);
|
||||
}
|
||||
|
||||
defineProps({
|
||||
src: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
links: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="embla" ref="emblaRef">
|
||||
<div class="embla__container">
|
||||
<EmblaItem v-for="el, i in src" :src="el" :link="links[i]" />
|
||||
</div>
|
||||
<button class="embla__button embla__button--prev" @click="prev">
|
||||
<span class="mobi-mbri mobi-mbri-arrow-prev" aria-hidden="true"></span>
|
||||
<span class="sr-only visually-hidden visually-hidden">Previous</span>
|
||||
</button>
|
||||
<button class="embla__button embla__button--next" @click="next">
|
||||
<span class="mobi-mbri mobi-mbri-arrow-next" aria-hidden="true"></span>
|
||||
<span class="sr-only visually-hidden visually-hidden">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
26
app/components/EmblaItem.vue
Normal file
26
app/components/EmblaItem.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
props: ["src", "link"],
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="embla__slide slider-image item"
|
||||
style="margin-left: 1rem; margin-right: 1rem"
|
||||
>
|
||||
<div class="slide-content">
|
||||
<div class="item-img">
|
||||
<div class="item-wrapper">
|
||||
<RouterLink :to="link">
|
||||
<img
|
||||
:src="
|
||||
src
|
||||
"
|
||||
/>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style></style>
|
||||
147
app/components/FormResults.vue
Normal file
147
app/components/FormResults.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<script lang="ts" setup>
|
||||
import RitzenbergenLib from "../ritzenbergenlib.ts";
|
||||
import { defineProps, ref, watchEffect } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: RitzenbergenLib.Formular,
|
||||
required: true,
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
|
||||
const form = ref(props.form);
|
||||
|
||||
|
||||
const results = ref([]);
|
||||
const myfields = ref([]);
|
||||
watchEffect(() => {
|
||||
fetch(
|
||||
RitzenbergenLib.RitzenbergenLib.api(
|
||||
"/formulare/get_results.php?id=" + form.value.id
|
||||
)
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
if(data.error){
|
||||
// Admin Rechte nötig
|
||||
fetch(RitzenbergenLib.RitzenbergenLib.api("/admin/formulare/ergebnisse.php?formular="+form.value.id),{
|
||||
headers: {
|
||||
"Authorization":props.token
|
||||
}
|
||||
})
|
||||
.then((res)=>res.json())
|
||||
.then((data)=>{
|
||||
results.value=data;
|
||||
})
|
||||
} else {
|
||||
results.value = data;
|
||||
}
|
||||
});
|
||||
|
||||
myfields.value = [];
|
||||
form.value.fields.forEach((field: RitzenbergenLib.Field) => {
|
||||
if (myfields.value.find((el) => el.name == field.name) == undefined) {
|
||||
myfields.value.push(field);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function prettyResult(result: any) {
|
||||
if (result == undefined) {
|
||||
return "";
|
||||
}
|
||||
if (result.value instanceof Array) {
|
||||
let tempresult = result.value;
|
||||
let cancel = false;
|
||||
tempresult = tempresult.map((el) => {
|
||||
let field = form.value.fields.find((f) => f.value == el);
|
||||
if (field == undefined) {
|
||||
cancel = true;
|
||||
return el;
|
||||
}
|
||||
return field.displayvalue ?? el;
|
||||
});
|
||||
if (!cancel) result.value = tempresult;
|
||||
|
||||
return result.value.join(", ");
|
||||
}
|
||||
if (result.type == "radio") {
|
||||
let field = form.value.fields.find((f) => f.value == result.value);
|
||||
if (field != undefined) {
|
||||
return field.displayvalue ?? result.value;
|
||||
}
|
||||
}
|
||||
return result.value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<h1>Ergebnisse {{ form.name }}</h1>
|
||||
<div class="main">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td v-for="(field, i) in myfields" :key="i">
|
||||
{{ field.displayname ?? field.name }}
|
||||
</td>
|
||||
<td>Zeitstempel</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(result, ri) in results" :key="ri">
|
||||
<td
|
||||
v-if="result.data != undefined"
|
||||
v-for="(field, fi) in myfields"
|
||||
:key="fi"
|
||||
:style="
|
||||
field.type == 'color'
|
||||
? {
|
||||
backgroundColor: result.data.find(
|
||||
(el) => el.name == field.name
|
||||
).value,
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
}
|
||||
: {}
|
||||
"
|
||||
>
|
||||
<span v-if="field.type != 'color'">{{
|
||||
prettyResult(
|
||||
result.data.find(
|
||||
(el) =>
|
||||
el.name == field.name ||
|
||||
el.name + "[]" == field.name
|
||||
)
|
||||
)
|
||||
}}</span>
|
||||
<span v-else></span>
|
||||
</td>
|
||||
<td>{{ result.timestamp }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@import "../assets/css/bulitipp2.css";
|
||||
td {
|
||||
min-width: 150px;
|
||||
min-height: 0;
|
||||
}
|
||||
tbody, table, .main{
|
||||
overflow-x: scroll;
|
||||
}
|
||||
thead tr td {
|
||||
background-color: #efefef;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
215
app/components/Kloenkasten.vue
Normal file
215
app/components/Kloenkasten.vue
Normal file
@@ -0,0 +1,215 @@
|
||||
<script lang="ts">
|
||||
import "../assets/css/chatbox.css";
|
||||
import RitzenbergenLib from "../ritzenbergenlib.ts";
|
||||
export default {
|
||||
name: "Kloenkasten",
|
||||
data() {
|
||||
return {
|
||||
sender: "",
|
||||
message: "",
|
||||
email: "",
|
||||
opened: false,
|
||||
reloader: false,
|
||||
RitzenbergenLib: RitzenbergenLib,
|
||||
msgrefs: [],
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
newMsg(): boolean {
|
||||
if (this.messages == undefined) return false;
|
||||
if (this.opened) this.open();
|
||||
const lastOpened: Date = new Date(
|
||||
parseInt(localStorage.getItem("kloenkasten_last_opened"))
|
||||
);
|
||||
const lastMsg = this.messages[this.messages.length - 1];
|
||||
if (this.messages && lastMsg.timestamp > lastOpened) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (localStorage.getItem("kloenkasten_last_opened") == null) {
|
||||
localStorage.setItem(
|
||||
"kloenkasten_last_opened",
|
||||
Date.now().toString()
|
||||
);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitMsg() {
|
||||
const url = new URL(
|
||||
RitzenbergenLib.RitzenbergenLib.api("/kloenkasten_submit.php")
|
||||
);
|
||||
url.searchParams.append("sender", this.sender);
|
||||
url.searchParams.append("email", this.email);
|
||||
url.searchParams.append("message", this.message);
|
||||
|
||||
fetch(url.toString(), { method: "GET" }).then(() => {
|
||||
this.reloader = !this.reloader;
|
||||
this.sender = "";
|
||||
this.email = "";
|
||||
this.message = "";
|
||||
});
|
||||
},
|
||||
open() {
|
||||
this.opened = true;
|
||||
|
||||
localStorage.setItem(
|
||||
"kloenkasten_last_opened",
|
||||
Date.now().toString()
|
||||
);
|
||||
if(this.messages) window.setTimeout(
|
||||
() =>
|
||||
this.msgrefs[this.msgrefs.length - 1].scrollIntoView({
|
||||
behavior: "smooth",
|
||||
}),
|
||||
50
|
||||
);
|
||||
},
|
||||
},
|
||||
asyncComputed: {
|
||||
messages: {
|
||||
get() {
|
||||
const url = new URL(
|
||||
RitzenbergenLib.RitzenbergenLib.api(
|
||||
"/kloenkasten_nachrichten.php"
|
||||
)
|
||||
);
|
||||
return fetch(url.toString(), { method: "GET" })
|
||||
.then((response)=>{
|
||||
if(response.ok) return response.json();
|
||||
else throw new Error("fetch "+response.status);
|
||||
})
|
||||
.then((data) =>
|
||||
data.map((msg) => {
|
||||
msg.timestamp = new Date(msg.timestamp);
|
||||
return msg;
|
||||
})
|
||||
).catch(()=>{
|
||||
return false;
|
||||
|
||||
});
|
||||
},
|
||||
watch: ["reloader"],
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<button
|
||||
id="chatbox-button"
|
||||
:class="{ newmsg: newMsg }"
|
||||
@click="open"
|
||||
>
|
||||
<span class="material-symbols-outlined">chat</span>
|
||||
|
||||
<span :class="{ newmsgdot: newMsg, newmsgdotinvis: !newMsg }"></span>
|
||||
</button>
|
||||
<div v-show="opened" id="modalbox">
|
||||
<div id="modalbox-header">
|
||||
<span class="material-symbols-outlined">chat</span>
|
||||
<h3 id="modalbox-title">Klönkasten</h3>
|
||||
<span id="close-button" @click="opened = false">×</span>
|
||||
</div>
|
||||
|
||||
<div id="chat-messages" v-if="messages">
|
||||
<div
|
||||
v-for="(msg, i) in messages"
|
||||
:key="i"
|
||||
:ref="(el) => (msgrefs[i] = el)"
|
||||
>
|
||||
<i>{{ msg.timestamp.toLocaleString() }}</i>
|
||||
<div class="message own-message animate__animated">
|
||||
<a :href="'mailto:' + msg.email" v-if="msg.email"
|
||||
>{{ msg.name }}:
|
||||
</a>
|
||||
<span class="message-sender animate__animated" v-else
|
||||
>{{ msg.name }}:
|
||||
</span>
|
||||
<span class="message-content animate__animated">{{
|
||||
msg.message
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<form id="chat-input" @submit.prevent="submitMsg">
|
||||
<input
|
||||
id="name-input"
|
||||
v-model="sender"
|
||||
type="text"
|
||||
maxlength="64"
|
||||
placeholder="Name"
|
||||
required
|
||||
/>
|
||||
<input
|
||||
id="email-input"
|
||||
v-model="email"
|
||||
type="email"
|
||||
maxlength="128"
|
||||
placeholder="E-Mail"
|
||||
/>
|
||||
<input
|
||||
id="message-input"
|
||||
v-model="message"
|
||||
type="text"
|
||||
placeholder="Nachricht"
|
||||
maxlength="1024"
|
||||
required
|
||||
/>
|
||||
<input type="submit" id="send-button" value="Senden" />
|
||||
</form>
|
||||
</div>
|
||||
<div id="chat-messages" v-else>
|
||||
<h3>Konnte Server nicht erreichen.</h3>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0");
|
||||
|
||||
.newmsg {
|
||||
animation: newmsgblink 3s infinite;
|
||||
}
|
||||
|
||||
.newmsgdot{
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: #00ff00;
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
z-index: 10;
|
||||
|
||||
}
|
||||
.newmsgdotinvis{
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes newmsgblink {
|
||||
0% {
|
||||
transform: scale(1) rotate(0deg) translateX(0) translateY(0);
|
||||
}
|
||||
20% {
|
||||
transform: scale(1.5) rotate(0deg) translateX(-10px) translateY(-10px);
|
||||
}
|
||||
25% {
|
||||
transform: scale(1.5) rotate(10deg) translateX(-10px) translateY(-10px);
|
||||
}
|
||||
30% {
|
||||
transform: scale(1.5) rotate(-10deg) translateX(-10px) translateY(-10px);
|
||||
}
|
||||
35% {
|
||||
transform: scale(1.5) rotate(10deg) translateX(-10px) translateY(-10px);
|
||||
}
|
||||
40% {
|
||||
transform: scale(1.5) rotate(-10deg) translateX(-10px) translateY(-10px);
|
||||
}
|
||||
45% {
|
||||
transform: scale(1.5) rotate(0deg) translateX(-10px) translateY(-10px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
29
app/components/Modal.vue
Normal file
29
app/components/Modal.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
emits: ["closemodal"],
|
||||
props: ["content"],
|
||||
mounted() {
|
||||
(<HTMLElement>this.$refs.contentspan)
|
||||
.querySelectorAll(".closelink")
|
||||
.forEach((el) => {
|
||||
el.addEventListener("click", () => {
|
||||
this.$emit("closemodal");
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="modal">
|
||||
<div class="modal-content">
|
||||
<button class="closeBtn" @click="$emit('closemodal')">x</button>
|
||||
<div class="modal-inner-content">
|
||||
<slot></slot>
|
||||
<span v-html="content" ref="contentspan"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="css" scoped>
|
||||
@import "../assets/modal";
|
||||
</style>
|
||||
79
app/components/MyFooter.vue
Normal file
79
app/components/MyFooter.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<script>
|
||||
import Modal from "./Modal.vue";
|
||||
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
aboutVisible: false,
|
||||
contactVisible: false,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
Modal,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<section
|
||||
class="footer3 cid-u6k7q0Blvk"
|
||||
once="footers"
|
||||
id="footer-6-u6k7q0Blvk"
|
||||
>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="row-links">
|
||||
<ul class="header-menu">
|
||||
<li class="header-menu-item mbr-fonts-style display-5">
|
||||
<Modal v-show="aboutVisible" @closemodal="aboutVisible = false">
|
||||
<br>
|
||||
<h1>Über</h1>
|
||||
<p>
|
||||
Ritzenbergen ist ein kleines Dorf der Gemeinde Blender und
|
||||
liegt dicht an der Weser.
|
||||
<br />
|
||||
<br />
|
||||
Bei dieser Seite handelt es sich um eine private Homepage der
|
||||
Dorfgemeinschaft Amedorf & Ritzenbergen.
|
||||
<br /><br />
|
||||
© Front-End und Web Design: Mathis Kuhlenkamp, Jonas Kuhlenkamp <br />
|
||||
© Back-End und Datenbanken: Jonas Kuhlenkamp
|
||||
<br />
|
||||
<br />
|
||||
|
||||
</p>
|
||||
<RouterLink to="/adminpanel/login">Admin Login</RouterLink>
|
||||
</Modal>
|
||||
|
||||
<button @click="aboutVisible=true" class="text-white btn-ueber openBtn">Über</button>
|
||||
</li>
|
||||
<li class="header-menu-item mbr-fonts-style display-5">
|
||||
<Modal
|
||||
v-show="contactVisible"
|
||||
@closemodal="contactVisible = false"
|
||||
>
|
||||
<h1>Kontakt</h1>
|
||||
<p>
|
||||
Tom Kuhlenkamp <br />
|
||||
tom@ritzenbergen.de
|
||||
</p>
|
||||
<br /><br />
|
||||
</Modal>
|
||||
<button
|
||||
class="text-white btn-kontakt openBtn"
|
||||
@click="contactVisible = true"
|
||||
>
|
||||
Kontakt
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-12 mt-4">
|
||||
<p class="mbr-fonts-style copyright display-7">
|
||||
© 2026 Ritzenbergen. Alle Rechte vorbehalten. <br />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<style></style>
|
||||
147
app/components/Navbar.vue
Normal file
147
app/components/Navbar.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<script lang="js">
|
||||
export default {
|
||||
name: "Navbar",
|
||||
props: {
|
||||
links: {
|
||||
type: Array,
|
||||
required: false,
|
||||
},
|
||||
buttontext: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
datalinks: [
|
||||
{ link: "/galerie", title: "Galerie" },
|
||||
{ link: "/umgebung", title: "Umgebung" },
|
||||
{ link: "/footer", title: "Kontakt" },
|
||||
{ link: "/bulitipp", title: "BuLi-Tipp" },
|
||||
],
|
||||
buttontextdata: "Über Ritzenbergen",
|
||||
isNavCollapsed: true,
|
||||
isCollapsing: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if(this.links) this.datalinks = this.links;
|
||||
if(this.buttontext) this.buttontextdata = this.buttontext;
|
||||
},
|
||||
methods: {
|
||||
clickmain(){
|
||||
if(this.buttontext){
|
||||
this.$emit("clickbtn");
|
||||
}else{
|
||||
this.$router.push("/willkommen");
|
||||
}
|
||||
},
|
||||
toggleCollapse(){
|
||||
/*if (this.isNavCollapsed) {
|
||||
document.body.classList.add("navbar-dropdown-open");
|
||||
} else {
|
||||
document.body.classList.remove("navbar-dropdown-open");
|
||||
}*/
|
||||
this.isCollapsing = true;
|
||||
this.isNavCollapsed = !this.isNavCollapsed;
|
||||
setTimeout(() => {
|
||||
this.isCollapsing = false;
|
||||
}, 300);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<section class="menu menu2 cid-u6k7q0wPq6" once="menu" id="menu-5-u6k7q0wPq6">
|
||||
<nav class="navbar navbar-dropdown navbar-fixed-top navbar-expand-lg" :class="{ opened: !isNavCollapsed }">
|
||||
<div class="container">
|
||||
<div class="navbar-brand">
|
||||
<span class="navbar-logo">
|
||||
<span href="/">
|
||||
<img
|
||||
class="navbar-logo-img"
|
||||
src="../assets/RitzenbergenOrtsschild.png"
|
||||
style="height: 60px; padding-left: 5px"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
<span class="navbar-caption-wrap">
|
||||
<span class="navbar-caption text-black display-4" href="/"
|
||||
>Amedorf & Ritzenbergen</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
:class="{ collapsed: isNavCollapsed }"
|
||||
type="button"
|
||||
data-toggle="collapse"
|
||||
data-bs-toggle="collapse"
|
||||
data-target="#navbarSupportedContent"
|
||||
data-bs-target="#navbarSupportedContent"
|
||||
aria-controls="navbarNavAltMarkup"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
@click="toggleCollapse"
|
||||
>
|
||||
<div class="hamburger">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</button>
|
||||
<div class="navbar-collapse opacityScroll" :class="{show: !isNavCollapsed, collapsing: isCollapsing, collapse: !isCollapsing}" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav nav-dropdown" data-app-modern-menu="true">
|
||||
<li class="nav-item" v-for="link in datalinks">
|
||||
<span
|
||||
class="nav-link link text-black display-4"
|
||||
:href="link.link"
|
||||
aria-expanded="false"
|
||||
>
|
||||
{{ link.title }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="navbar-buttons mbr-section-btn">
|
||||
<span class="btn btn-primary display-4" @click="clickmain"
|
||||
>{{ buttontextdata }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</section>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
font-family: "Inter Tight";
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
font-weight: 600;
|
||||
}
|
||||
.link {
|
||||
font-weight: 400;
|
||||
}
|
||||
#navbarSupportedContent {
|
||||
transition: all 0.2s ease-in-out;
|
||||
height: auto;
|
||||
}
|
||||
#navbarSupportedContent:not(.show) {
|
||||
max-height: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#navbarSupportedContent.show {
|
||||
max-height: 1000px;
|
||||
padding: 16px;
|
||||
|
||||
}
|
||||
@media (min-width: 1201px) {
|
||||
#navbarSupportedContent {
|
||||
max-height: 1000px !important;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
36
app/components/admin/AdminNavbar.vue
Normal file
36
app/components/admin/AdminNavbar.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ref } from "vue";
|
||||
import AdminPanelLib from "../../adminpanellib.ts";
|
||||
import Navbar from "../Navbar.vue";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const token=ref(route.params.token);
|
||||
const userinfo=ref({})
|
||||
|
||||
AdminPanelLib.AdminPanelLib.getUserInfo(token.value)
|
||||
.then((result)=>{
|
||||
if(result) return result;
|
||||
else router.push({"path":"/adminpanel/login"});
|
||||
})
|
||||
.then((result)=>userinfo.value=result);
|
||||
|
||||
const links=[
|
||||
{ "title":"Startseite", "link":"/adminpanel/"+token.value },
|
||||
{ "title":"Formulare", "link":"/adminpanel/"+token.value+"/formulare" },
|
||||
{ "title":"Events", "link":"/adminpanel/"+token.value+"/events" }
|
||||
]
|
||||
|
||||
function logout(){
|
||||
router.push({"path":"/adminpanel/login"});
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<Navbar :links="links" buttontext="Abmelden" @clickbtn="logout"/>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
64
app/components/admin/InputP.vue
Normal file
64
app/components/admin/InputP.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, defineProps, computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: [String,Boolean,Number],
|
||||
default: null,
|
||||
},
|
||||
nullable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
inputtype: {
|
||||
type: String,
|
||||
default: "text",
|
||||
required: false
|
||||
}
|
||||
});
|
||||
|
||||
const firstValue = props.modelValue;
|
||||
|
||||
const isNull = ref(firstValue == null);
|
||||
|
||||
const emit = defineEmits(["update:modelValue", "isNull"]);
|
||||
|
||||
const value = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (v) => {
|
||||
emit("update:modelValue", v);
|
||||
},
|
||||
});
|
||||
|
||||
if(value.value==null && props.nullable==false){
|
||||
isNull.value=false;
|
||||
value.value="";
|
||||
}
|
||||
|
||||
const editing = ref(false);
|
||||
</script>
|
||||
<template>
|
||||
<form v-if="editing" @submit.prevent="editing = false">
|
||||
<input
|
||||
:type="props.inputtype"
|
||||
:placeholder="firstValue"
|
||||
v-model="value"
|
||||
v-if="!isNull"
|
||||
/>
|
||||
<label for="nullCheckbox" v-if="nullable">Null: </label>
|
||||
<input
|
||||
id="nullCheckbox"
|
||||
type="checkbox"
|
||||
v-if="nullable"
|
||||
@change="value=isNull?null:value"
|
||||
v-model="isNull"
|
||||
/>
|
||||
<input type="submit" value="Speichern" />
|
||||
</form>
|
||||
<i v-else-if="value=='' && !isNull && props.inputtype!='checkbox'" @dblclick="editing=true">EMPTY</i>
|
||||
<p v-else-if="!isNull" @dblclick="editing = true">{{ value }}</p>
|
||||
<i v-else @dblclick="editing = true">NULL</i>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
106
app/components/bulitipp/Loading.vue
Normal file
106
app/components/bulitipp/Loading.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="loading-container">
|
||||
<div class="loading-main">
|
||||
<h1>Lade...</h1>
|
||||
<div class="dots-bars-6"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
h1{
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
.loading-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 100;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
}
|
||||
.loading-main{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 50%;
|
||||
width: 50%;
|
||||
background-color: white;
|
||||
border-radius: 20px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.dots-bars-6 {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
--c:radial-gradient(farthest-side,currentColor 93%,#0000);
|
||||
background:
|
||||
var(--c) 0 0,
|
||||
var(--c) 50% 0;
|
||||
background-size:8px 8px;
|
||||
background-repeat: no-repeat;
|
||||
position: relative;
|
||||
clip-path: inset(-200% -100% 0 0);
|
||||
animation: db6-0 1.5s linear infinite;
|
||||
}
|
||||
.dots-bars-6:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 12px;
|
||||
background:currentColor;
|
||||
left:-16px;
|
||||
top:0;
|
||||
animation:
|
||||
db6-1 1.5s linear infinite,
|
||||
db6-2 0.5s cubic-bezier(0,200,.8,200) infinite;
|
||||
}
|
||||
.dots-bars-6:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset:0 0 auto auto;
|
||||
width:8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background:currentColor;
|
||||
animation: db6-3 1.5s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes db6-0 {
|
||||
0%,30% {background-position: 0 0 ,50% 0 }
|
||||
33% {background-position: 0 100%,50% 0 }
|
||||
41%,63% {background-position: 0 0 ,50% 0 }
|
||||
66% {background-position: 0 0 ,50% 100%}
|
||||
74%,100%{background-position: 0 0 ,50% 0 }
|
||||
}
|
||||
|
||||
@keyframes db6-1 {
|
||||
90% {transform:translateY(0)}
|
||||
95% {transform:translateY(15px)}
|
||||
100% {transform:translateY(15px);left:calc(100% - 8px)}
|
||||
}
|
||||
|
||||
@keyframes db6-2 {
|
||||
100% {top:-0.1px}
|
||||
}
|
||||
|
||||
@keyframes db6-3 {
|
||||
0%,80%,100% {transform:translate(0)}
|
||||
90% {transform:translate(26px)}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
161
app/components/bulitipp/Paarungsergebnisse.vue
Normal file
161
app/components/bulitipp/Paarungsergebnisse.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<script lang="js">
|
||||
import RitzenbergenLib from "../../ritzenbergenlib.ts";
|
||||
import Modal from "../Modal.vue";
|
||||
export default {
|
||||
props: {
|
||||
ergebnisse: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
maxspieltag: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
tipps: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
users: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
RitzenbergenLib,
|
||||
showmodal: false,
|
||||
modalindex: 0,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
Modal,
|
||||
},
|
||||
methods: {
|
||||
ps(heim, gast, ergebnisHeim, ergebnisGast) {
|
||||
if(heim == ergebnisHeim && gast == ergebnisGast) {
|
||||
return 3;
|
||||
}
|
||||
const tippDiff = heim - gast;
|
||||
const ergebnisDiff = ergebnisHeim - ergebnisGast;
|
||||
if(tippDiff === ergebnisDiff) {
|
||||
return 2;
|
||||
}
|
||||
if(heim > gast && ergebnisHeim > ergebnisGast) {
|
||||
return 1;
|
||||
}
|
||||
if(heim < gast && ergebnisHeim < ergebnisGast) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<section class="buli-results scroll-x" id="buliresults-section">
|
||||
<br /><br />
|
||||
<h2>Paarungsergebnisse {{ maxspieltag }}. Spieltag</h2>
|
||||
<Modal v-if="showmodal" @closemodal="showmodal = false">
|
||||
<h1 class="detailansichtSchriftart">
|
||||
Detailansicht {{ maxspieltag }}. Spieltag
|
||||
</h1>
|
||||
<h2 class="detailansichtSchriftart">
|
||||
{{ ergebnisse[modalindex].paarung.heim }} -
|
||||
{{ ergebnisse[modalindex].paarung.gast }}
|
||||
</h2>
|
||||
<h1>
|
||||
{{ ergebnisse[modalindex].heim }} -
|
||||
{{ ergebnisse[modalindex].gast }}
|
||||
</h1>
|
||||
<table class="detailansichtSchriftart">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>Tipp</td>
|
||||
<td>Punkte</td>
|
||||
<td>Gesamtpunktzahl</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-for="(tipp, i) in tipps.filter(
|
||||
(tipp) =>
|
||||
tipp.tipp.paarungsid ==
|
||||
ergebnisse[modalindex].paarung.id
|
||||
)"
|
||||
:key="i"
|
||||
>
|
||||
<td>
|
||||
{{
|
||||
users.filter((user) => user.id == tipp.user)[0]
|
||||
.username
|
||||
}}
|
||||
</td>
|
||||
<td>{{ tipp.tipp.heim }} - {{ tipp.tipp.gast }}</td>
|
||||
<td>{{ ps(tipp.tipp.heim, tipp.tipp.gast, ergebnisse[modalindex].heim, ergebnisse[modalindex].gast) }}</td>
|
||||
<td>
|
||||
{{
|
||||
users.filter((user) => user.id == tipp.user)[0]
|
||||
.points
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Modal>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Paarung</td>
|
||||
<td>Ergebnis</td>
|
||||
</tr>
|
||||
<tr v-for="(ergebnis, i) in ergebnisse" :key="i">
|
||||
<td
|
||||
@click="
|
||||
showmodal = true;
|
||||
modalindex = i;
|
||||
"
|
||||
>
|
||||
<span class="as-link">
|
||||
<span class="teams">
|
||||
<span class="team">
|
||||
<img
|
||||
:src="
|
||||
RitzenbergenLib.RitzenbergenLib.api(
|
||||
'/bulitipp/get-image.php?team=' +
|
||||
ergebnis.paarung.heim
|
||||
)
|
||||
"
|
||||
alt=""
|
||||
/>
|
||||
<p>{{ ergebnis.paarung.heim }}</p>
|
||||
</span>
|
||||
<span class="vs"></span>
|
||||
<span class="team">
|
||||
<p>{{ ergebnis.paarung.gast }}</p>
|
||||
<img
|
||||
:src="
|
||||
RitzenbergenLib.RitzenbergenLib.api(
|
||||
'/bulitipp/get-image.php?team=' +
|
||||
ergebnis.paarung.gast
|
||||
)
|
||||
"
|
||||
alt=""
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<p>{{ ergebnis.heim }} - {{ ergebnis.gast }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</template>
|
||||
<style scoped>
|
||||
@import "../../assets/css/bulitipp2.css";
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
98
app/components/bulitipp/Rangliste.vue
Normal file
98
app/components/bulitipp/Rangliste.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<script lang="ts">
|
||||
import ritzenbergenlib from '../../ritzenbergenlib';
|
||||
import Modal from '../Modal.vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
users: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
spieltag: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
results: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
tipps: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
modalOpen: false,
|
||||
currentuser: null
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Modal
|
||||
},
|
||||
methods: {
|
||||
getById(results,paarungsid){
|
||||
return results.find((result) => {
|
||||
return result.paarung.id === paarungsid;
|
||||
});
|
||||
},
|
||||
},
|
||||
asyncComputed: {
|
||||
spiele: {
|
||||
get(){
|
||||
if(this.spieltag==null) return;
|
||||
if(this.currentuser==null) return;
|
||||
return ritzenbergenlib.Spiel.fetchSpiele(this.spieltag-1, this.currentuser.id);
|
||||
},
|
||||
watch: ["spieltag","currentuser"],
|
||||
default: []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<section class="rangliste" id="rangliste-sektion">
|
||||
<br /><br />
|
||||
<Modal v-if="modalOpen" @closemodal="modalOpen = false">
|
||||
<h1 class="detailansichtSchriftart">Detailansicht für {{ currentuser.username }}, {{ spieltag }}. Spieltag</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Tipps von {{ currentuser.username }}</td>
|
||||
<td>Ergebnis</td>
|
||||
<td>Tipp</td>
|
||||
<td>Punkte</td>
|
||||
</tr>
|
||||
<tr v-for="(spiel,i) in spiele">
|
||||
<td>{{ spiel.paarung.heim }} - {{ spiel.paarung.gast }}</td>
|
||||
<td>{{ spiel.result[0] }} - {{ spiel.result[1] }}</td>
|
||||
<td v-if="spiel.tipp!=null">{{ spiel.tipp[0] }} - {{ spiel.tipp[1] }}</td>
|
||||
<td v-else>-</td>
|
||||
<td>{{ spiel.calcPoints() }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</Modal>
|
||||
<h2>Rangliste</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Platz</td>
|
||||
<td>Name</td>
|
||||
<td>Punkte</td>
|
||||
</tr>
|
||||
<tr v-for="(user, i) in users">
|
||||
<td>{{ i+1 }}</td>
|
||||
<td @click="modalOpen=true; currentuser=user">
|
||||
<span class="as-link">{{ user.username }}</span>
|
||||
</td>
|
||||
<td>{{ user.points }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</template>
|
||||
<style scoped>
|
||||
@import "../../assets/css/bulitipp2.css";
|
||||
</style>
|
||||
105
app/components/bulitipp/Tabelle.vue
Normal file
105
app/components/bulitipp/Tabelle.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<script lang="ts">
|
||||
import ritzenbergenlib from "../../ritzenbergenlib";
|
||||
import Modal from "../Modal.vue";
|
||||
export default {
|
||||
props: {
|
||||
users: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
ts: {
|
||||
type: null,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
closeModal(){
|
||||
this.modalOpen=false;
|
||||
},
|
||||
openModal(spieltag, user){
|
||||
this.modalOpen=true;
|
||||
this.spieltag=spieltag;
|
||||
this.user=user;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
Modal,
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
modalOpen: false,
|
||||
spieltag: null,
|
||||
user: null,
|
||||
RitzenbergenLib: ritzenbergenlib.RitzenbergenLib
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
asyncComputed: {
|
||||
modalContent: {
|
||||
get(): Array<ritzenbergenlib.Spiel>{
|
||||
if(this.spieltag==undefined) return [];
|
||||
return ritzenbergenlib.Spiel.fetchSpiele(this.spieltag,this.ts[this.spieltag][this.user].user.id);
|
||||
},
|
||||
default: []
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<Modal v-if="modalOpen" @closemodal="closeModal"
|
||||
><h1 class="detailansichtSchriftart">
|
||||
Detailansicht für {{ ts[spieltag][user].user.username }},
|
||||
{{ spieltag + 1 }}. Spieltag
|
||||
</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Tipp von {{ ts[spieltag][user].user.username }}</td>
|
||||
<td>Ergebnis</td>
|
||||
<td>Tipp</td>
|
||||
<td>Punkte</td>
|
||||
</tr>
|
||||
<tr v-for="spiel in modalContent">
|
||||
<td>{{ spiel.paarung.heim }} - {{ spiel.paarung.gast }}</td>
|
||||
<td>{{ spiel.result[0] }} - {{ spiel.result[1] }}</td>
|
||||
<td v-if="spiel.tipp!=null">{{ spiel.tipp[0] }} - {{ spiel.tipp[1] }}</td>
|
||||
<td v-else> - </td>
|
||||
<td>{{ spiel.calcPoints() }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</Modal>
|
||||
<section class="buli-table" id="buli-table">
|
||||
<br /><br />
|
||||
<h2>Punktetabelle</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Tag</td>
|
||||
<td v-for="spieltag in ts[0]">{{ spieltag.user.username }}</td>
|
||||
</tr>
|
||||
<tr v-for="(spieltag, i) in ts">
|
||||
<td>{{ i + 1 }}</td>
|
||||
|
||||
<!-- Open BTN -->
|
||||
<td
|
||||
class="as-link"
|
||||
v-for="(userpoints, j) in spieltag"
|
||||
@click="openModal(i, j)"
|
||||
>
|
||||
{{ userpoints.tsPoints }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Summe</td>
|
||||
|
||||
<td v-for="user in users">{{ user.points }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</template>
|
||||
<style scoped>
|
||||
@import "../../assets/css/bulitipp2.css";
|
||||
</style>
|
||||
229
app/components/bulitipp/Tippen.vue
Normal file
229
app/components/bulitipp/Tippen.vue
Normal file
@@ -0,0 +1,229 @@
|
||||
<script lang="ts">
|
||||
import ritzenbergenlib from "../../ritzenbergenlib";
|
||||
import "../../assets/css/bulitipp2.css";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
token: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
spieltag: "",
|
||||
vmodelspieltag: "",
|
||||
tipps: [
|
||||
new ritzenbergenlib.Tipp(null, null, null),
|
||||
new ritzenbergenlib.Tipp(null, null, null),
|
||||
new ritzenbergenlib.Tipp(null, null, null),
|
||||
new ritzenbergenlib.Tipp(null, null, null),
|
||||
new ritzenbergenlib.Tipp(null, null, null),
|
||||
new ritzenbergenlib.Tipp(null, null, null),
|
||||
new ritzenbergenlib.Tipp(null, null, null),
|
||||
new ritzenbergenlib.Tipp(null, null, null),
|
||||
new ritzenbergenlib.Tipp(null, null, null)
|
||||
],
|
||||
disabled: false,
|
||||
schongetippt: true
|
||||
};
|
||||
},
|
||||
asyncComputed: {
|
||||
userinfo: {
|
||||
get() {
|
||||
if (this.token == null) return null;
|
||||
return fetch(
|
||||
ritzenbergenlib.RitzenbergenLib.api(
|
||||
"/bulitipp/userinfo.php?token=" + this.token
|
||||
)
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.catch((error) => {
|
||||
console.error("Error fetching user info:", error);
|
||||
return null;
|
||||
});
|
||||
},
|
||||
default: null,
|
||||
},
|
||||
paarungen: {
|
||||
get() {
|
||||
if (this.spieltag == null) return null;
|
||||
return fetch(
|
||||
ritzenbergenlib.RitzenbergenLib.api(
|
||||
"/bulitipp/paarungen.php?spieltag=" + this.spieltag
|
||||
)
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((response) => response.data)
|
||||
.then((response) =>
|
||||
response.map((el) => {
|
||||
return new ritzenbergenlib.Paarung(el[0], el[1], el[2]);
|
||||
})
|
||||
);
|
||||
},
|
||||
default: null,
|
||||
},
|
||||
maxtippspieltag: {
|
||||
get(){
|
||||
return fetch(
|
||||
ritzenbergenlib.RitzenbergenLib.api(
|
||||
"/bulitipp/maxtippspieltag.php"
|
||||
)
|
||||
)
|
||||
.then((response) => response.text())
|
||||
.then((text)=> parseInt(text))
|
||||
}
|
||||
},
|
||||
maxspieltag: {
|
||||
get(){
|
||||
return fetch(
|
||||
ritzenbergenlib.RitzenbergenLib.api(
|
||||
"/bulitipp/maxspieltag.php"
|
||||
)
|
||||
)
|
||||
.then((response) => response.text())
|
||||
.then((text)=> parseInt(text))
|
||||
}
|
||||
},
|
||||
mintippspieltag: {
|
||||
get(): number {
|
||||
if(this.maxspieltag==34){
|
||||
this.disabled = true;
|
||||
return 1;
|
||||
}else{
|
||||
this.disabled = false;
|
||||
return this.maxspieltag + 1;
|
||||
}
|
||||
},
|
||||
watch: ["maxspieltag"]
|
||||
},
|
||||
tippupdater:{
|
||||
get(){
|
||||
const params = new URLSearchParams({
|
||||
spieltag: this.spieltag.toString()
|
||||
});
|
||||
|
||||
return fetch(
|
||||
ritzenbergenlib.RitzenbergenLib.api(
|
||||
"/bulitipp/tippsuser.php?" + params.toString()),
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: "Bearer " + this.token,
|
||||
},
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((response) => {
|
||||
if (response.length > 0) {
|
||||
return response.map((el:any) => {
|
||||
if(el==null){
|
||||
this.schongetippt = false;
|
||||
return new ritzenbergenlib.Tipp(null, null, null);
|
||||
}
|
||||
this.schongetippt=true;
|
||||
return new ritzenbergenlib.Tipp(
|
||||
el.paarung,
|
||||
el.score1,
|
||||
el.score2
|
||||
);
|
||||
});
|
||||
}
|
||||
}).then(response=>{
|
||||
this.tipps=response;
|
||||
return response;
|
||||
});
|
||||
},
|
||||
watch: ["spieltag"]
|
||||
},
|
||||
zeitzutippen: {
|
||||
get(){
|
||||
return fetch(
|
||||
ritzenbergenlib.RitzenbergenLib.api(
|
||||
"/bulitipp/zeitzutippen.php"
|
||||
)
|
||||
)
|
||||
.then((response) => response.json());
|
||||
}
|
||||
}
|
||||
},
|
||||
emits: ["logout"],
|
||||
methods: {
|
||||
getTeamImage(team: string) {
|
||||
return ritzenbergenlib.RitzenbergenLib.api(
|
||||
"/bulitipp/get-image.php?team=" + team
|
||||
);
|
||||
},
|
||||
async tippen(){
|
||||
this.tipps.forEach((tipp, i) => {
|
||||
tipp.paarung = this.paarungen[i];
|
||||
});
|
||||
|
||||
const params = new URLSearchParams({
|
||||
spieltag: this.spieltag.toString(),
|
||||
tipps: JSON.stringify(this.tipps)
|
||||
});
|
||||
|
||||
let result=await fetch(
|
||||
ritzenbergenlib.RitzenbergenLib.api("/bulitipp/tippeintragen.php?"+params.toString()),
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: "Bearer " + this.token,
|
||||
},
|
||||
}
|
||||
);
|
||||
this.spieltag = "";
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="(spieltag == '' || spieltag == null) && userinfo != null">
|
||||
<h1>Moin {{ userinfo.username }}!</h1>
|
||||
<br />
|
||||
<h4 v-if="zeitzutippen!=null">Du hast noch <span v-if="zeitzutippen.days!=0">{{ zeitzutippen.days }} Tage und </span>{{ zeitzutippen.hours }} Stunden Zeit, den {{ zeitzutippen.spieltag }}. Spieltag zu tippen.</h4>
|
||||
<br />
|
||||
<div v-if="disabled">
|
||||
<h3>Gerade kann nicht getippt werden.</h3><br>
|
||||
</div>
|
||||
<form @submit.prevent="spieltag = parseInt(vmodelspieltag)">
|
||||
<input
|
||||
type="number"
|
||||
v-model="vmodelspieltag"
|
||||
:placeholder="'Spieltag (max: '+maxtippspieltag+')'"
|
||||
:min="mintippspieltag"
|
||||
:max="maxtippspieltag"
|
||||
required
|
||||
:disabled="disabled"
|
||||
/>
|
||||
<input type="submit" value="Tippen" :disabled="disabled" />
|
||||
<br /><br />
|
||||
<input type="button" value="Ausloggen" @click="$emit('logout')" class="red-button" />
|
||||
</form>
|
||||
</div>
|
||||
<div class="tippenEintragen" v-else>
|
||||
<form @submit.prevent="tippen" id="mainform">
|
||||
<span class="paarung" v-for="(paarung,i) in paarungen" :key="paarung.id">
|
||||
<img :src="getTeamImage(paarung.heim)" alt="" />
|
||||
<span class="team-name">{{ paarung.heim }}</span>
|
||||
|
||||
<input v-model="tipps[i].heim" type="number" min="0" class="score" required />
|
||||
<span class="vs"></span>
|
||||
<input v-model="tipps[i].gast" type="number" min="0" class="score" required />
|
||||
<span class="team-name">{{ paarung.gast }}</span>
|
||||
<img :src="getTeamImage(paarung.gast)" alt="" /><br />
|
||||
</span>
|
||||
<input type="submit" :value="schongetippt?'Tipps aktualisieren':'Tippen'" class="green-button"/>
|
||||
<br /><br />
|
||||
<input type="button" value="Abbrechen" @click="spieltag = ''" class="red-button" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
img {
|
||||
width: 30px;
|
||||
}
|
||||
</style>
|
||||
40
app/components/bulitipp/TippenEinloggen.vue
Normal file
40
app/components/bulitipp/TippenEinloggen.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<script lang="ts">
|
||||
import CryptoJS from 'crypto-js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
kuerzel: "",
|
||||
password: ""
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
login(){
|
||||
this.$emit("login", this.kuerzel, CryptoJS.SHA256(this.password).toString(CryptoJS.enc.Hex));
|
||||
this.kuerzel="";
|
||||
this.password="";
|
||||
}
|
||||
},
|
||||
props: {
|
||||
wrongpassword: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ["login"]
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<h1>Einloggen</h1>
|
||||
<form @submit.prevent="login">
|
||||
<input type="text" placeholder="Kürzel" v-model="kuerzel" required />
|
||||
<input type="password" placeholder="Passwort" v-model="password" required />
|
||||
<input type="submit" value="Einloggen">
|
||||
<div v-if="wrongpassword">
|
||||
Falsches Passwort oder Kürzel! Bitte versuche es erneut.
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
72
app/components/bulitipp/Uebersicht.vue
Normal file
72
app/components/bulitipp/Uebersicht.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<script lang="ts">
|
||||
import Modal from "../Modal.vue"
|
||||
export default {
|
||||
props: {
|
||||
users: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
spieltag: {
|
||||
type: Number,
|
||||
required: false
|
||||
},
|
||||
tipps: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
paarungen: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
currentuser: null,
|
||||
modalOpen: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Modal
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<section class="uebersicht scroll-x">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td v-for="user in users" @click="currentuser=user; modalOpen=true">{{ user.kuerzel }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td v-for="user in users" :style='{"color": user.hatgetippt()?"green":"red"}' @click="currentuser=user; modalOpen=true">{{ user.points }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<Modal v-if="modalOpen" @closemodal="modalOpen=false">
|
||||
<div v-if="spieltag!=undefined">
|
||||
<h1>Detailansicht für {{ currentuser.username }}, {{ spieltag }}. Spieltag</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Paarung</td>
|
||||
<td>Tipp von {{ currentuser.username }}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="tipp, i in tipps.filter(t=>t.user==currentuser.id)">
|
||||
<td>{{ paarungen[i].heim }} - {{ paarungen[i].gast }}</td>
|
||||
<td>{{ tipp.tipp.heim }} - {{ tipp.tipp.gast }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div v-else>
|
||||
<h1>Lade...</h1>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
<style scoped>
|
||||
|
||||
@import "../../assets/css/bulitipp2.css";
|
||||
</style>
|
||||
111
app/components/startseite/Bilderbuch.vue
Normal file
111
app/components/startseite/Bilderbuch.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<script lang="ts" setup>
|
||||
import RitzenbergenLib from "../../ritzenbergenlib.ts";
|
||||
import {ref} from "vue";
|
||||
|
||||
async function loadImage(path: string) {
|
||||
try{
|
||||
const response = await fetch(RitzenbergenLib.RitzenbergenLib.api(path), {
|
||||
headers: {
|
||||
"Accept":"image/png"
|
||||
}
|
||||
});
|
||||
if(!response.ok) return false;
|
||||
const blob = await response.blob();
|
||||
return URL.createObjectURL(blob);
|
||||
|
||||
}
|
||||
catch(e){
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
loadImage("randomimage.php?path=/doppelkopf&recursive=1&tn=1&color=white&text=Doppelkopf&size=3").then((url)=>{
|
||||
images.value[0]=url;
|
||||
});
|
||||
loadImage("randomimage.php?path=/erntefest&recursive=1&tn=1&color=white&text=Erntefest&size=3").then((url)=>{
|
||||
images.value[1]=url;
|
||||
});
|
||||
loadImage("randomimage.php?path=/fussball&recursive=1&tn=1&color=white&text=Fußballturnier&size=3").then((url)=>{
|
||||
images.value[2]=url;
|
||||
});
|
||||
loadImage("randomimage.php?path=/osterfeuer&recursive=1&tn=1&color=white&text=Osterfeuer&size=3").then((url)=>{
|
||||
images.value[3]=url;
|
||||
});
|
||||
|
||||
const images=ref([]);
|
||||
</script>
|
||||
<template>
|
||||
<section
|
||||
class="gallery09 cid-u6k7q0xbqP"
|
||||
id="gallery-9-u6k7q0xbqP"
|
||||
v-if="images[0]"
|
||||
>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-12 col-lg-4 main-text">
|
||||
<div class="">
|
||||
<h5
|
||||
class="mbr-section-title mbr-fonts-style mt-0 mb-4 display-2"
|
||||
>
|
||||
<strong>Bilderbuch Ritzenbergen</strong>
|
||||
</h5>
|
||||
<h6
|
||||
class="mbr-section-subtitle mbr-fonts-style mt-0 mb-4 display-7"
|
||||
>
|
||||
Klicke auf ein Bild um in unsere Galerie zu
|
||||
gelangen. Die Bilder sind nach Jahreszahl und
|
||||
Kategorie geordnet.
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-8 side-features row">
|
||||
<div
|
||||
class="item features-image col-12 col-md-6 col-lg-6 active"
|
||||
>
|
||||
<div class="item-wrapper">
|
||||
<div class="item-img">
|
||||
<RouterLink to="/galerie/doppelkopf"
|
||||
><img :src="images[0]"
|
||||
/></RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item features-image col-12 col-md-6 col-lg-6 active"
|
||||
>
|
||||
<div class="item-wrapper">
|
||||
<div class="item-img">
|
||||
<RouterLink to="/galerie/erntefest"
|
||||
><img :src="images[1]"
|
||||
/></RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item features-image col-12 col-md-6 col-lg-6 active"
|
||||
>
|
||||
<div class="item-wrapper">
|
||||
<div class="item-img">
|
||||
<RouterLink to="/galerie/fussball"
|
||||
><img :src="images[2]"
|
||||
/></RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="item features-image col-12 col-md-6 col-lg-6 active"
|
||||
>
|
||||
<div class="item-wrapper">
|
||||
<div class="item-img">
|
||||
<RouterLink to="/galerie/osterfeuer"
|
||||
><img :src="images[3]"
|
||||
/></RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<style></style>
|
||||
162
app/components/startseite/Events.vue
Normal file
162
app/components/startseite/Events.vue
Normal file
@@ -0,0 +1,162 @@
|
||||
<script lang="ts" setup>
|
||||
import RitzenbergenLib from "../../ritzenbergenlib";
|
||||
import Modal from "../Modal.vue";
|
||||
import MarkdownRender from "vue-renderer-markdown";
|
||||
import "katex/dist/katex.min.css";
|
||||
import Forms from "./Forms.vue";
|
||||
import { ref } from "vue";
|
||||
import { EventType, MyEvent } from "../../dto/event.dto.js";
|
||||
|
||||
const initdone=ref(false);
|
||||
|
||||
const events = ref<MyEvent[]>([]);
|
||||
|
||||
const openedModals=ref<number[]>([]);
|
||||
|
||||
const modaltypes=[EventType.html,EventType.markdown];
|
||||
|
||||
async function init() {
|
||||
|
||||
events.value=(await RitzenbergenLib.graphqlClient.request<{events: MyEvent[]}>
|
||||
(`{
|
||||
events {
|
||||
id
|
||||
eventname
|
||||
type
|
||||
minitext
|
||||
datum
|
||||
content
|
||||
link
|
||||
foto
|
||||
formular
|
||||
}
|
||||
}`)).events;
|
||||
console.log(events.value);
|
||||
|
||||
|
||||
}
|
||||
|
||||
init().then(()=>{
|
||||
|
||||
initdone.value=true;
|
||||
|
||||
});
|
||||
|
||||
function format_date(date: string){
|
||||
return new Date(date).toDateString();
|
||||
}
|
||||
|
||||
function vorschautext(str: string){
|
||||
return str;
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<section class="features03 cid-u6k7q0xyDG" id="news-1-u6k7q0xyDG" v-if="initdone">
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center mb-5">
|
||||
<div class="col-12 content-head">
|
||||
<div class="mbr-section-head">
|
||||
<h4
|
||||
class="mbr-section-title mbr-fonts-style align-center mb-0 display-2"
|
||||
>
|
||||
<strong>Termine & Neuigkeiten</strong>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="events">
|
||||
<!-- Events -->
|
||||
|
||||
<h5 class="align-center" v-if="events.length == 0">
|
||||
Es stehen keine Events an.
|
||||
</h5>
|
||||
|
||||
<div
|
||||
v-for="(event, i) in events"
|
||||
:key="i"
|
||||
class="item features-image col-12 col-md-6 col-lg-3"
|
||||
:class="{ active: i % 4 == 0 }"
|
||||
>
|
||||
<Modal
|
||||
v-show="
|
||||
openedModals.includes(event.id) &&
|
||||
modaltypes.includes(event.type)
|
||||
"
|
||||
@closemodal="
|
||||
openedModals.splice(
|
||||
openedModals.indexOf(event.id),
|
||||
1
|
||||
)
|
||||
"
|
||||
>
|
||||
<MarkdownRender
|
||||
v-if="event.type == EventType.markdown"
|
||||
:content="event.content"
|
||||
/>
|
||||
<div v-else v-html="event.content"></div>
|
||||
<Forms v-if="event.formular" :formid="event.formular"/>
|
||||
</Modal>
|
||||
|
||||
<div class="item-wrapper">
|
||||
<div class="item-img mb-3">
|
||||
<img :src="RitzenbergenLib.RitzenbergenLib.get_img(event.foto)" />
|
||||
</div>
|
||||
<div class="item-content align-left">
|
||||
<h6
|
||||
class="item-subtitle mbr-fonts-style mt-0 mb-3 display-5"
|
||||
>
|
||||
<strong
|
||||
><a
|
||||
class="text-black fw-bold"
|
||||
:data-id="event.id"
|
||||
>{{ event.eventname }}</a
|
||||
></strong
|
||||
>
|
||||
</h6>
|
||||
<p class="mbr-text mbr-fonts-style mb-3 display-7">
|
||||
{{ format_date(event.datum) }}
|
||||
</p>
|
||||
<p class="mbr-text mbr-fonts-style mb-3 display-7">
|
||||
{{ vorschautext(event.minitext) }}
|
||||
</p>
|
||||
<div class="mbr-section-btn item-footer">
|
||||
<a
|
||||
:download="
|
||||
event.type == 'dlink'
|
||||
? event.link
|
||||
: undefined
|
||||
"
|
||||
:href="event.link"
|
||||
><button
|
||||
class="btn item-btn btn-primary display-7"
|
||||
:data-id="event.id"
|
||||
@click="openedModals.push(event.id)"
|
||||
>
|
||||
<span v-if="event.type == 'link'"
|
||||
>Einladung öffnen</span
|
||||
>
|
||||
<span v-else-if="event.type == 'dlink'"
|
||||
>Einladung runterladen</span
|
||||
>
|
||||
<span
|
||||
v-else-if="event.type == 'fotos'"
|
||||
@click="galerie(event.content)"
|
||||
>Fotos ansehen</span
|
||||
>
|
||||
<span v-else>Mehr</span>
|
||||
</button></a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-else>
|
||||
<h1>Keine Internetverbindung!</h1>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<style></style>
|
||||
184
app/components/startseite/Forms.vue
Normal file
184
app/components/startseite/Forms.vue
Normal file
@@ -0,0 +1,184 @@
|
||||
<script lang="ts" setup>
|
||||
import RitzenbergenLib from "../../ritzenbergenlib";
|
||||
import FormResults from "../FormResults.vue";
|
||||
import { ref } from "vue";
|
||||
import Modal from "../Modal.vue";
|
||||
import { Formular } from "../../dto/formular.dto";
|
||||
|
||||
async function init() {
|
||||
forms.value=await RitzenbergenLib.graphqlClient.request<{formulare: Formular[] }>(`
|
||||
{
|
||||
formulare {
|
||||
id
|
||||
name
|
||||
minitext
|
||||
ispublic
|
||||
fields {
|
||||
id
|
||||
name
|
||||
displayname
|
||||
displayvalue
|
||||
placeholder
|
||||
type
|
||||
title
|
||||
required
|
||||
maxlength
|
||||
min
|
||||
max
|
||||
checked
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
).then(data=>data.formulare);
|
||||
|
||||
console.log(forms.value);
|
||||
}
|
||||
|
||||
const forms = ref([] as Formular[]);
|
||||
|
||||
const props=defineProps({
|
||||
formid: {
|
||||
type: [Number, null],
|
||||
required: false,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
|
||||
init();
|
||||
|
||||
function submit($event: Event) {
|
||||
const url = new URL(
|
||||
RitzenbergenLib.RitzenbergenLib.api("/formulare/submit.php")
|
||||
);
|
||||
const formData = new FormData(<HTMLFormElement>$event.target);
|
||||
fetch(url.toString(), {
|
||||
method: "POST",
|
||||
body: formData
|
||||
}).then(() => {
|
||||
init();
|
||||
values.value={};
|
||||
});
|
||||
}
|
||||
|
||||
const modalOpened=ref<boolean>(false);
|
||||
|
||||
const openedForm=ref<Formular|null>(null);
|
||||
|
||||
function openModal(form: Formular){
|
||||
openedForm.value=form;
|
||||
modalOpened.value=true;
|
||||
}
|
||||
|
||||
const values=ref({});
|
||||
</script>
|
||||
<template>
|
||||
<Modal v-if="openedForm && openedForm.ispublic" v-show="modalOpened" @closemodal="modalOpened=false">
|
||||
<FormResults v-if="modalOpened" :form="openedForm"/>
|
||||
</Modal>
|
||||
<section ref="anmeldeformular" id="anmeldeformular">
|
||||
<section class="form5 cid-u6k7q0BfGa">
|
||||
<div class="container" v-for="(form, i) in forms" :key="i">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 content-head">
|
||||
<div class="mbr-section-head mb-5">
|
||||
<h3
|
||||
class="mbr-section-title mbr-fonts-style align-center mb-0 display-2"
|
||||
>
|
||||
<strong>{{ form.name }}</strong>
|
||||
</h3>
|
||||
<br />
|
||||
<h5 style="text-align: center">
|
||||
<b @click="openModal(form)" class="fakelink" v-if="form.ispublic">{{ form.minitext }}
|
||||
</b> <b v-else>{{ form.minitext }}</b> <br />
|
||||
</h5>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div
|
||||
class="col-lg-8 mx-auto mbr-form"
|
||||
data-form-type="formoid"
|
||||
>
|
||||
<form
|
||||
class="mbr-form form-with-styler"
|
||||
data-form-title="Form Name"
|
||||
:data-formid="form.id"
|
||||
:data-i="i"
|
||||
@submit.prevent="submit"
|
||||
>
|
||||
<div v-for="(field, j) in form.fields" :key="j">
|
||||
<label
|
||||
v-if="field.placeholder == null"
|
||||
:for="'field-' + field.id"
|
||||
>
|
||||
{{
|
||||
field.displayvalue ?? field.displayname ?? field.name
|
||||
}}:
|
||||
<span v-if="field.type == 'range'"
|
||||
><br />{{ values[field.id] }}</span
|
||||
>
|
||||
</label>
|
||||
<FormKit
|
||||
v-if="field.type != 'textarea'"
|
||||
:id="'field-' + field.id"
|
||||
:type="field.type"
|
||||
:name="field.name"
|
||||
:placeholder="field.placeholder"
|
||||
:required="field.required"
|
||||
:maxlength="field.maxlength"
|
||||
:min="field.min"
|
||||
:max="field.max"
|
||||
:checked="field.checked"
|
||||
:title="field.title"
|
||||
:value="field.value"
|
||||
v-model="values[field.id]"
|
||||
|
||||
/>
|
||||
<textarea
|
||||
v-else
|
||||
:id="'field-' + field.id"
|
||||
:name="field.name"
|
||||
:placeholder="field.placeholder"
|
||||
:required="field.required"
|
||||
:maxlength="field.maxlength"
|
||||
:title="field.title"
|
||||
:value="field.value"
|
||||
></textarea>
|
||||
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="col-lg-12 col-md-12 col-sm-12 align-center mbr-section-btn"
|
||||
>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary display-7 formular-submit-button"
|
||||
>
|
||||
Absenden
|
||||
</button>
|
||||
</div>
|
||||
<input type="hidden" :value="form.id" name="internalformid" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</template>
|
||||
<style scoped>
|
||||
label {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.fakelink{
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
60
app/components/startseite/Jarallax.vue
Normal file
60
app/components/startseite/Jarallax.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div class="parallax-wrapper">
|
||||
<div
|
||||
class="jarallax"
|
||||
ref="parallaxEl"
|
||||
data-speed="0.5"
|
||||
>
|
||||
<div class="jarallax-img" style="background-image: url('https://ritzenbergen.de/Fotos/erntefest2011.jpg');">
|
||||
|
||||
</div>
|
||||
<div class="container content cid-u6k7q0zosO">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { jarallax } from 'jarallax';
|
||||
import 'jarallax/dist/jarallax.css'; // optional, falls du Styles möchtest
|
||||
|
||||
export default {
|
||||
name: 'ParallaxSection',
|
||||
mounted() {
|
||||
jarallax(this.$refs.parallaxEl);
|
||||
},
|
||||
beforeDestroy() {
|
||||
jarallax(this.$refs.parallaxEl, 'destroy');
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.parallax-wrapper {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.jarallax-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
slot{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
82
app/components/startseite/Umgebung.vue
Normal file
82
app/components/startseite/Umgebung.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<script>
|
||||
import Jarallax from './Jarallax.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Jarallax,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Jarallax>
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="card col-12 col-md-12 col-lg-10">
|
||||
<div class="card-wrapper">
|
||||
<div class="card-box align-center">
|
||||
<h1 class="card-title mbr-fonts-style mb-4 display-1">
|
||||
<strong style="color: black;">Entdecke die Umgebung</strong>
|
||||
</h1>
|
||||
<p class="mbr-text mbr-fonts-style mb-4 display-7">
|
||||
Hier findest du nützliche Links aus der Umgebung
|
||||
</p>
|
||||
<section class="umgebung">
|
||||
<div>
|
||||
<ul>
|
||||
<b>
|
||||
<li><a href="https://alt-blender.de" target="_blank">alt-blender.de - Historische Fotos und
|
||||
Dokumente aus
|
||||
Blender und umzu</a></li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="https://www.verden.de/" target="_blank">Verden/Aller</a></li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="https://www.langwedel.de/" target="_blank">Flecken Langwedel</a></li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="https://www.feuerwehr-blender.de/" target="_blank">Freiwillige Feuerwehr
|
||||
Blender</a></li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="https://www.browiede.de/" target="_blank">Landgasthaus Browiede</a></li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="https://www.mittelweserverband.de/" target="_blank">Mittelweserverband</a></li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="http://angelverein-doerverden.de/" target="_blank">Angelverein Dörverden</a></li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="https://www.theater-holtum.de/" target="_blank">Theatergruppe des gemischten
|
||||
Chores "Polyhymnia"
|
||||
Holtum Marsch</a></li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="https://www.thedinghausen.de/" target="_blank">Samtgemeinde Thedinghausen</a>
|
||||
</li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="https://www.tsv-blender.de/">TSV Blender</a></li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="https://tsvintschede.de-zign.de/">TSV "Weserstrand" Intschede</a></li>
|
||||
</b>
|
||||
<b>
|
||||
<li><a href="https://www.intscheder-bauernhofeis.de/">Intscheder Bauernhofeis</a></li>
|
||||
</b>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Jarallax>
|
||||
</template>
|
||||
<style>
|
||||
li{
|
||||
list-style: none;
|
||||
}
|
||||
</style>
|
||||
43
app/components/startseite/Willkommen.vue
Normal file
43
app/components/startseite/Willkommen.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<script lang="ts">
|
||||
|
||||
export default {
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<section
|
||||
class="header16 cid-u6k7q0xIhk mbr-fullscreen mbr-parallax-background"
|
||||
id="hero-17-u6k7q0xIhk"
|
||||
>
|
||||
<div
|
||||
class="mbr-overlay"
|
||||
style="opacity: 0.3; background-color: rgb(0, 0, 0)"
|
||||
></div>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="content-wrap col-12 col-md-10">
|
||||
<h1
|
||||
class="mbr-section-title mbr-fonts-style mbr-white mb-4 display-1"
|
||||
>
|
||||
<strong>Willkommen auf ritzenbergen.de</strong>
|
||||
</h1>
|
||||
<p class="mbr-fonts-style mbr-text mbr-white mb-4 display-7">
|
||||
Dies ist eine private Homepage über das Dorfleben in Amedorf und
|
||||
Ritzenbergen
|
||||
</p>
|
||||
<div class="mbr-section-btn">
|
||||
<a
|
||||
class="btn btn-white-outline display-7"
|
||||
href="#gallery-9-u6k7q0xbqP"
|
||||
>Erkunden</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
27
app/components/startseite/WillkommenText.vue
Normal file
27
app/components/startseite/WillkommenText.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<section class="article12 cid-u6k7q0yKNv" id="about-us-12-u6k7q0yKNv">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-12 col-lg-10">
|
||||
<h3 class="mbr-section-title mbr-fonts-style mb-4 mt-0 display-2">
|
||||
<strong>Willkommen in Ritzenbergen</strong>
|
||||
</h3>
|
||||
<p class="mbr-text mbr-fonts-style display-7">Ritzenbergen, ehemalig "Rikinburg" wurde nur ein einziges Mal im
|
||||
Jahr 935 in der historischen Überlieferung erwähnt. In diesem Jahr wurde sie vom Edelherren Willarius der
|
||||
Bremer Kirche geschenkt. Eine Identifikation dieser Burg mit einem auf einer Karte des Amtes Thedinghausen
|
||||
von 1765 eingetragenen Hügel von etwa 150 m Durchmesser oberhalb eines alten Weserarms in Ritzenbergen ist
|
||||
aber bisher nicht gesichert.</p>
|
||||
<p class="mbr-text mbr-fonts-style display-7">Die Gemeinde Amedorf/Ritzenbergen wurde zusammen mit der
|
||||
Gemeinde Holtum-Marsch im Jahr 1968 in die Gemeinde Blender eingegliedert.</p>
|
||||
<p class="mbr-text mbr-fonts-style display-7">In der Galerie findest du viele Fotos aus den letzten Jahren.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user