mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-05 07:19:49 +00:00
separate vue logic into different components
This commit is contained in:
parent
af3d06e7d3
commit
13c33567fd
@ -161,7 +161,7 @@ export interface LocationType {
|
||||
title: TranslatableString;
|
||||
}
|
||||
|
||||
export interface NewsItem {
|
||||
export interface NewsItemType {
|
||||
id: number;
|
||||
title: string;
|
||||
content: string;
|
||||
|
@ -2,27 +2,7 @@
|
||||
<div>
|
||||
<h1>{{ $t('widget.news.title') }}</h1>
|
||||
<ul class="scrollable">
|
||||
<li v-for="item in newsItems" :key="item.id">
|
||||
<h2>{{ item.title }}</h2>
|
||||
<div class="content" v-if="shouldTruncate(item.content)">
|
||||
<div v-html="prepareContent(item.content)"></div>
|
||||
<span class="read-more" @click="() => openModal(item)">{{ $t('widget.news.readMore') }}</span>
|
||||
</div>
|
||||
<div class="content" v-else>
|
||||
<div v-html="convertMarkdownToHtml(item.content)"></div>
|
||||
</div>
|
||||
<modal v-if="showModal" @close="closeModal">
|
||||
<template #header>
|
||||
<p class="news-title">{{ item.title }}</p>
|
||||
</template>
|
||||
<template #body>
|
||||
<p class="news-date">
|
||||
{{ $t('widget.news.date') }}: <span>{{ formatDate(item.startdate.date) }}</span>
|
||||
</p>
|
||||
<div v-html="convertMarkdownToHtml(item.content)"></div>
|
||||
</template>
|
||||
</modal>
|
||||
</li>
|
||||
<NewsItem v-for="item in newsItems" :item="item" :key="item.id" />
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
@ -30,54 +10,15 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { makeFetch } from '../../../lib/api/apiMethods';
|
||||
import Modal from '../../_components/Modal.vue'; // Adjust the import path
|
||||
import { marked } from 'marked';
|
||||
import DOMPurify from 'dompurify';
|
||||
import {DateTime, NewsItem} from '../../../types';
|
||||
import Modal from '../../_components/Modal.vue';
|
||||
import { NewsItemType } from '../../../types';
|
||||
import NewsItem from './NewsItem.vue';
|
||||
|
||||
const newsItems = ref<NewsItem[]>([])
|
||||
const selectedArticle = ref<NewsItem | null>(null);
|
||||
const showModal = ref(false);
|
||||
|
||||
const openModal = (item: NewsItem) => {
|
||||
selectedArticle.value = item;
|
||||
showModal.value = true;
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
selectedArticle.value = null;
|
||||
showModal.value = false;
|
||||
};;
|
||||
|
||||
const shouldTruncate = (content: string, maxLength = 100): boolean => {
|
||||
return content.length > maxLength;
|
||||
};
|
||||
|
||||
const truncateContent = (content: string, maxLength = 100): string => {
|
||||
if (shouldTruncate(content, maxLength)) {
|
||||
return content.slice(0, maxLength) + '...';
|
||||
} else {
|
||||
return content;
|
||||
}
|
||||
};
|
||||
|
||||
const convertMarkdownToHtml = (markdown: string): string => {
|
||||
const rawHtml = marked(markdown);
|
||||
return DOMPurify.sanitize(rawHtml)
|
||||
};
|
||||
|
||||
const prepareContent = (content: string, maxLength = 100): string => {
|
||||
const truncatedContent = truncateContent(content, maxLength);
|
||||
return convertMarkdownToHtml(truncatedContent);
|
||||
};
|
||||
|
||||
const formatDate = (datetime: DateTime): string => {
|
||||
return new Date(datetime.toString()).toLocaleDateString('fr-FR')
|
||||
}
|
||||
const newsItems = ref<NewsItemType[]>([])
|
||||
|
||||
onMounted(() => {
|
||||
makeFetch('GET', '/api/1.0/main/news.json')
|
||||
.then((response: { results: NewsItem[] }) => {
|
||||
.then((response: { results: NewsItemType[] }) => {
|
||||
// console.log('news articles', response.results)
|
||||
newsItems.value = response.results
|
||||
})
|
||||
@ -94,46 +35,13 @@ ul {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-height: 100px; /* Adjust the max height as needed */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/*
|
||||
.scrollable {
|
||||
overflow-y: auto;
|
||||
max-height: 150px; /* Same as .content max-height */
|
||||
margin-bottom: 10px; /* To give space for the scrollbar */
|
||||
max-height: 150px; !* Same as .content max-height *!
|
||||
margin-bottom: 10px; !* To give space for the scrollbar *!
|
||||
}
|
||||
*/
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
background-color: #3498db;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.read-more {
|
||||
color: #3498db; /* Adjust the color as needed */
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.news-date {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.news-title {
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<li>
|
||||
<h2>{{ props.item.title }}</h2>
|
||||
<div class="content" v-if="shouldTruncate(item.content)">
|
||||
<div v-html="prepareContent(item.content)"></div>
|
||||
<span class="read-more" @click="() => openModal(item)">{{ $t('widget.news.readMore') }}</span>
|
||||
</div>
|
||||
<div class="content" v-else>
|
||||
<div v-html="convertMarkdownToHtml(item.content)"></div>
|
||||
</div>
|
||||
|
||||
<modal v-if="showModal" @close="closeModal">
|
||||
<template #header>
|
||||
<p class="news-title">{{ item.title }}</p>
|
||||
</template>
|
||||
<template #body>
|
||||
<p class="news-date">
|
||||
{{ $t('widget.news.date') }}: <span>{{ formatDate(item.startdate.date) }}</span>
|
||||
</p>
|
||||
<div v-html="convertMarkdownToHtml(item.content)"></div>
|
||||
</template>
|
||||
</modal>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
|
||||
import { marked } from 'marked';
|
||||
import DOMPurify from 'dompurify';
|
||||
import { DateTime, NewsItemType } from "../../../types";
|
||||
import type { PropType } from 'vue'
|
||||
import { defineProps, ref } from "vue";
|
||||
import {dateToISO} from "../../../chill/js/date";
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object as PropType<NewsItemType>,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const selectedArticle = ref<NewsItemType | null>(null);
|
||||
const showModal = ref(false);
|
||||
|
||||
const openModal = (item: NewsItemType) => {
|
||||
selectedArticle.value = item;
|
||||
showModal.value = true;
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
selectedArticle.value = null;
|
||||
showModal.value = false;
|
||||
};
|
||||
|
||||
const shouldTruncate = (content: string, maxLength = 100): boolean => {
|
||||
return content.length > maxLength;
|
||||
};
|
||||
|
||||
const truncateContent = (content: string, maxLength = 100): string => {
|
||||
if (shouldTruncate(content, maxLength)) {
|
||||
const lastSpaceIndex = content.lastIndexOf(' ', maxLength);
|
||||
console.log(lastSpaceIndex)
|
||||
|
||||
if (lastSpaceIndex !== -1) {
|
||||
return content.slice(0, lastSpaceIndex) + '...';
|
||||
} else {
|
||||
return content.slice(0, maxLength) + '...';
|
||||
}
|
||||
} else {
|
||||
return content;
|
||||
}
|
||||
};
|
||||
|
||||
const convertMarkdownToHtml = (markdown: string): string => {
|
||||
const rawHtml = marked(markdown);
|
||||
return DOMPurify.sanitize(rawHtml)
|
||||
};
|
||||
|
||||
const prepareContent = (content: string, maxLength = 100): string => {
|
||||
const truncatedContent = truncateContent(content, maxLength);
|
||||
return convertMarkdownToHtml(truncatedContent);
|
||||
};
|
||||
|
||||
const formatDate = (datetime: DateTime): string|null => {
|
||||
return dateToISO(new Date(datetime.toString()))
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
li {
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-height: 100px; /* Adjust the max height as needed */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
background-color: #3498db;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.read-more {
|
||||
color: #3498db; /* Adjust the color as needed */
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.news-date {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.news-title {
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user