update(News Widget/Content stylings): updates the style of the news widget and single news view

This commit is contained in:
SimonGschnell
2025-07-22 09:47:45 +02:00
parent 07d610d60f
commit 117a284dc4
5 changed files with 219 additions and 52 deletions
+8 -23
View File
@@ -158,32 +158,17 @@
.carousel-control-prev,
.carousel-control-next {
opacity: 0;
transition: opacity 0.3s ease;
top: 0.5rem !important;
bottom: auto !important;
opacity: 1 !important;
}
/* Show the buttons when the carousel is hovered */
.carousel:hover .carousel-control-prev,
.carousel:hover .carousel-control-next {
opacity: 1;
.fhc-news-items-lg .row:hover{
background-color: var(--fhc-primary);
color: var(--fhc-light);
cursor: pointer;
}
.fhc-news-text{
font-size: 0.75em;
}
.fhc-news-items-sm{
.fhc-news-xs {
font-size: 0.6em;
}
.fhc-news-sm {
font-size: 0.7em;
}
.fhc-news-md {
font-size: 1.1em;
}
.fhc-news-lg {
font-size: 1.4em;
}
+4 -1
View File
@@ -1,7 +1,7 @@
import raum_contentmittitel from './Content_types/Raum_contentmittitel.js'
import general from './Content_types/General.js'
import BsConfirm from "../../Bootstrap/Confirm.js";
import news_content from './Content_types/News_content.js';
import ApiCms from '../../../api/factory/cms.js';
export default {
@@ -22,6 +22,7 @@ export default {
},
components: {
raum_contentmittitel,
news_content,
general,
},
data() {
@@ -80,6 +81,8 @@ export default {
switch (this.content_type) {
case "raum_contentmittitel":
return "raum_contentmittitel";
case "news":
return "news_content";
default:
return "general";
};
@@ -0,0 +1,142 @@
import { replaceRelativeLegacyLink } from "../../../../helpers/LegacyLinkReplaceHelper.js"
export default {
name: "GeneralComponent",
props:{
content:{
type:String,
required:true,
},
},
methods: {
sanitizeLegacyTables(table) {
// find nested tables and replace with p element
const tt = table.querySelectorAll('table')
tt.forEach(t => {
const textContent = t.textContent.trim();
const pElement = document.createElement('p');
pElement.textContent = textContent;
t.parentNode.replaceChild(pElement, t);
})
// find unordered lists, traverse li childs and replace with p element -> more readable than 1 p tag for ul
const ul = table.querySelectorAll('ul')
ul.forEach(u => {
Array.from(u.children).forEach(li => {
const p = document.createElement('p');
p.textContent = li.textContent
u.parentNode.appendChild(p)
})
u.parentNode.removeChild(u)
})
// find bare text nodes and put into p element
const td = Array.from(table.querySelectorAll('td')).filter(el => el.scrollWidth > 100)
td.forEach(element => {
if (element.firstChild?.nodeType === Node.TEXT_NODE && element.firstChild.length > 10) {
const p = document.createElement('p');
p.appendChild(element.firstChild)
element.appendChild(p);
}
});
// flatten nested th elements
const ths = Array.from(table.querySelectorAll('th'))
ths.forEach(th => {
if(th.children.length > 1) {
th.innerHTML = Array.from(th.childNodes).find(cn => cn.textContent).textContent
}
})
// let p elements wrap on overflow
const p = table.querySelectorAll('p')
p.forEach(p => {
p.style.setProperty('word-wrap', 'break-word');
p.style.setProperty('white-space', 'normal');
p.style.setProperty('max-width', '400px');
})
}
},
mounted(){
// replaces the tablesorter with the tabulator
let tables = Array.from(document.getElementsByClassName("tablesorter"));
tables.forEach((table, index) => {
this.sanitizeLegacyTables(table)
new Tabulator(table, {
index: index,
layout: "fitDataFill",
columnDefaults: {
formatter: "html",
resizable: true,
minWidth: "100px"
}
})
})
document.querySelectorAll("#cms [data-confirm]").forEach((el) => {
el.addEventListener("click", (evt) => {
evt.preventDefault();
BsConfirm.popup(el.dataset.confirm)
.then(() => {
Axios.get(el.href)
.then((res) => {
// TODO(chris): check for success then show message and/or reload
location = location;
})
.catch((err) => console.error("ERROR:", err));
})
.catch(() => {});
});
});
document.querySelectorAll("#cms [data-href]").forEach((el) => {
el.href = el.dataset.href.replace(
/^ROOT\//,
FHC_JS_DATA_STORAGE_OBJECT.app_root
);
});
document.querySelectorAll("[href]").forEach((element) => {
let orignal_href = element.getAttribute("href");
let new_href = replaceRelativeLegacyLink(orignal_href);
element.href = new_href;
});
document.querySelectorAll("[style*=background-color]").forEach((element) => {
if (element.style.backgroundColor == "rgb(255, 255, 255)"){
element.style.backgroundColor = "var(--fhc-background)";
}
if(element.querySelector("*[style*=background-color]")){
element.style.backgroundColor = "var(--fhc-tertiary)";
}
});
Vue.nextTick(() => {
document.querySelectorAll(".card-header").forEach((el) => {
el.classList.add("fhc-primary");
});
document.querySelectorAll(".row").forEach((el) => {
el.classList.add("w-100");
el.classList.add("align-items-center");
});
document.querySelectorAll(".row h2").forEach((el) => {
el.classList.add("mb-0");
});
})
},
template: /*html*/ `
<!-- div that contains the content -->
<div v-if="content" class="container" style="max-width: 100%;"><div class="row"><div class="col">
<div v-html="content" ></div>
</div></div></div>
<p v-else>Content was not found</p>
`,
};
+2 -2
View File
@@ -164,7 +164,7 @@ export default {
</Transition>
<span class="col mx-2 px-2">{{ widget.setup.name }}</span>
<template v-if="isPinned">
<div type="button" v-if="editMode" pinned="true" @click="unpin" v-tooltip="{showDelay:1000, value: 'unpin item'}" aria-label="unpin item" class="pin cursor-pointer col-auto me-2">
<div type="button" role="button" v-if="editMode" pinned="true" @click="unpin" title="unpin item" aria-label="unpin item" class="pin cursor-pointer col-auto me-2">
<i class="fa-solid fa-thumbtack " aria-hidden="true"></i>
</div>
<div v-else class="col-auto me-2">
@@ -172,7 +172,7 @@ export default {
</div>
</template>
<template v-else>
<div type="button" v-if="editMode" class="col-auto me-2 pin" @click="pinItem" aria-label="pin item" v-tooltip="{showDelay:1000, value: 'pin item'}">
<div type="button" role="button" v-if="editMode" class="col-auto me-2 pin" @click="pinItem" aria-label="pin item" title="pin item">
<i class="fa-solid fa-thumbtack" aria-hidden="true" style="color:lightgray;"></i>
</div>
</template>
+63 -26
View File
@@ -36,7 +36,12 @@ export default {
quantity = this.height === 1 ? 4 : MAX_LOADED_NEWS;
}
return this.allNewsList.slice(0, quantity);
let slicedNews= this.allNewsList.slice(0, quantity);
slicedNews.sort((a,b)=>{
return new Date(b.insertamum) - new Date(a.insertamum);
});
return slicedNews;
},
carouselItems() {
return this.allNewsList.reduce((acc, cur) => {
@@ -47,6 +52,14 @@ export default {
}
},
methods: {
formatDate: function (dateTime) {
const dt = new Date(dateTime);
return dt.getDate() + '.' + (dt.getMonth() + 1) + '.' + dt.getFullYear();
},
formatTime: function (dateTime) {
const dt = new Date(dateTime);
return dt.getHours() + ':' + dt.getMinutes();
},
isString(value){
return Object.prototype.toString.call(value) === '[object String]';
},
@@ -141,6 +154,25 @@ export default {
this.allNewsList = Array.from(Object.values(news));
this.selected = this.allNewsList.length ? this.allNewsList[0] : null
this.initActiveItem()
Vue.nextTick(() => {
document.querySelectorAll(".fhc-news-card-item .card-body, .fhc-news-card-item .card, .fhc-news-card-item .card-header").forEach((el) => {
el.classList.add("border-0");
});
document.querySelectorAll(".fhc-news-card-item .card-header").forEach((el) => {
el.classList.add("px-5");
el.classList.add("fhc-primary");
});
document.querySelectorAll(".fhc-news-card-item .card-header .row").forEach((el) => {
el.classList.add("w-100");
el.classList.add("align-items-center");
});
document.querySelectorAll(".fhc-news-card-item .card-header .row h2").forEach((el) => {
el.classList.add("mb-0");
});
})
})
.catch((err) => {
@@ -167,32 +199,37 @@ export default {
}
this.initCarouselInstance()
},
template: /*html*/ `
<div ref="container" class="widgets-news h-100" :class="sizeClass" :style="getNewsWidgetStyle">
<div class="d-flex flex-column h-100">
<div class="h-100" style="overflow-y: auto" v-show="width == 1">
<div v-for="(news, index) in newsList" :key="news.news_id" class="mt-2">
<div v-if="index > 0 " class="fhc-seperator"></div>
<a :href="contentURI(news.content_id)" >{{ news.content_obj.betreff?news.content_obj.betreff:getDate(news.insertamum) }}</a><br>
<span class="small text-muted">{{ formatDateTime(news.insertamum) }}</span>
<div class="h-100 fhc-news-items-sm" style="overflow-y: auto" v-show="width == 1" >
<div v-for="(news, index) in newsList" :key="news.news_id" class="py-2">
<div class="row m-0">
<div class="col-3 d-flex">
<span class="small">{{ formatDate(news.insertamum) }} </span>
<span class="ms-auto small">{{ formatTime(news.insertamum) }} </span>
</div>
<div class="col">
<a :href="contentURI(news.content_id)" >{{ news.content_obj.betreff?news.content_obj.betreff:getDate(news.insertamum) }}</a>
</div>
</div>
</div>
</div>
<div v-show="width >1" class="row h-100 g-0">
<div :class="'col-'+(width == 2? 6 : 4) + ' h-100 g-0'" style="overflow: auto;">
<template v-for="news in newsList" :key="'menu-'+news.news_id">
<div class="position-relative">
<div class="row fhc-news-menu-item " @click="setSelected(news)" :class="getMenuItemClass(news)" style="margin-right: 0px; margin-left: 0px; overflow-y: hidden;">
<div class="col-8 fhc-news-menu-item-betreff">
<p class="fhc-news-text mb-0">
{{news.content_obj.betreff ?? ''}}
</p>
</div>
<span style="top:2px; right:0" class=" position-absolute d-none d-xl-block fhc-news-text fhc-news-menu-item-date fw-bold">
{{ news.datumformatted ?? ''}}
</span>
</div>
<div :class="'col-'+(width == 2? 6 : 4) + ' h-100 g-0'" style="overflow: auto;" class="fhc-news-items-lg border-end" >
<template v-for="news in newsList" :key="'menu-'+news.news_id" >
<div class="row m-0 py-2" @click="setSelected(news)">
<div class="col-3 d-flex">
<span class="small">{{ formatDate(news.insertamum) }} </span>
<span class="ms-auto small">{{ formatTime(news.insertamum) }} </span>
</div>
<div class="col">
<span >{{ news.content_obj.betreff?news.content_obj.betreff:getDate(news.insertamum) }}</span>
</div>
</div>
</template>
</div>
<div :class="'col-'+(width == 2? 6 : 8) + ' h-100'" style="padding-left: 0px; padding-right: 0px;" ref="htmlContent">
@@ -200,16 +237,16 @@ export default {
<div id="FhcCarouselContainer" style="height: 100%;" ref="carousel" class="carousel slide fhc-carousel" data-bs-interval="false">
<div class="carousel-inner" ref="carouselInner" style="height: 100%; max-width: 100%;">
<div ref="carouselItems" v-for="(news, index) in newsList" class="carousel-item " style="overflow-y: auto; overflow-x: hidden; height: 100%;" :id="'card-'+news.news_id" v-html="news.content_obj.content"/>
<div ref="carouselItems" v-for="(news, index) in newsList" class="carousel-item fhc-news-card-item" style="overflow-y: auto; overflow-x: hidden; height: 100%;" :id="'card-'+news.news_id" v-html="news.content_obj.content"/>
</div>
<button @click="setPrev" @focus="$event.target.blur()" style="z-index: 100; color: black; overflow: hidden; margin-left: 10px; width:35px;" data-bs-target="#FhcCarouselContainer" class="carousel-control-prev" type="button">
<div class="border rounded-circle" style="padding-left: 0.4rem; padding-right: 0.4rem; background-color:rgba(138,138,138,0.4)">
<i class="fa fa-chevron-left"></i>
<button @click="setPrev" style="z-index: 100; overflow: hidden; margin-left: 4px; width:35px;" data-bs-target="#FhcCarouselContainer" class="carousel-control-prev" type="button">
<div style="padding-left: 0.4rem; padding-right: 0.4rem;">
<i class="fa fa-chevron-left fhc-text-light"></i>
</div>
</button>
<button @click="setNext" @focus="$event.target.blur()" style="z-index: 100; color: black; overflow: hidden; margin-right: 10px; width:35px;" data-bs-target="#FhcCarouselContainer" class="carousel-control-next" type="button">
<div class="border rounded-circle" style="padding-left: 0.4rem; padding-right: 0.4rem; background-color:rgba(138,138,138,0.4)">
<i class="fa fa-chevron-right"></i>
<button @click="setNext" style="z-index: 100; overflow: hidden; margin-right: 4px; width:35px;" data-bs-target="#FhcCarouselContainer" class="carousel-control-next" type="button">
<div style="padding-left: 0.4rem; padding-right: 0.4rem;">
<i class="fa fa-chevron-right fhc-text-light"></i>
</div>
</button>
</div>