Refactor backend CORS settings to include default origins and improve error handling in chat services: Introduce dynamic CORS origin handling, enhance RabbitMQ message sending with fallback mechanisms, and update WebSocket service to manage pending messages. Update UI components for better accessibility and responsiveness, including adjustments to dialog and navigation elements. Enhance styling for improved user experience across various components.
This commit is contained in:
@@ -1,34 +1,43 @@
|
||||
<template>
|
||||
<div class="blog-view">
|
||||
<div v-if="loading">Laden…</div>
|
||||
<div v-else>
|
||||
<h1>{{ blog.title }}</h1>
|
||||
<p v-if="blog.description">{{ blog.description }}</p>
|
||||
<div class="meta">von {{ blog.owner?.username }}</div>
|
||||
<div v-if="$store.getters.isLoggedIn" class="actions">
|
||||
<router-link class="editbutton" v-if="isOwner" :to="{ name: 'BlogEdit', params: { id: blog.id } }">Bearbeiten</router-link>
|
||||
</div>
|
||||
<div class="posts">
|
||||
<h2>{{ $t('blog.posts') }}</h2>
|
||||
<div v-if="!items.length">{{ $t('blog.noPosts') }}</div>
|
||||
<article v-for="p in items" :key="p.id" class="post">
|
||||
<h3>{{ p.title }}</h3>
|
||||
<div class="content" v-html="sanitize(p.content)" />
|
||||
</article>
|
||||
<div class="pagination" v-if="total > pageSize">
|
||||
<div v-if="loading" class="blog-view__state surface-card">Laden…</div>
|
||||
<div v-else-if="blog" class="blog-layout">
|
||||
<section class="blog-hero surface-card">
|
||||
<div>
|
||||
<div class="meta">von {{ blog.owner?.username }}</div>
|
||||
<h1>{{ blog.title }}</h1>
|
||||
<p v-if="blog.description" class="blog-description">{{ blog.description }}</p>
|
||||
</div>
|
||||
<div v-if="$store.getters.isLoggedIn" class="actions">
|
||||
<router-link class="editbutton" v-if="isOwner" :to="{ name: 'BlogEdit', params: { id: blog.id } }">Bearbeiten</router-link>
|
||||
</div>
|
||||
</section>
|
||||
<div class="blog-content">
|
||||
<section class="posts surface-card">
|
||||
<div class="posts__header">
|
||||
<h2>{{ $t('blog.posts') }}</h2>
|
||||
<span class="posts__count">{{ total }} Eintraege</span>
|
||||
</div>
|
||||
<div v-if="!items.length" class="blog-view__state">Keine Eintraege vorhanden.</div>
|
||||
<article v-for="p in items" :key="p.id" class="post">
|
||||
<h3>{{ p.title }}</h3>
|
||||
<div class="content" v-html="sanitize(p.content)" />
|
||||
</article>
|
||||
<div class="pagination" v-if="total > pageSize">
|
||||
<button :disabled="page===1" @click="go(page-1)">«</button>
|
||||
<span>{{ page }} / {{ pages }}</span>
|
||||
<button :disabled="page===pages" @click="go(page+1)">»</button>
|
||||
</div>
|
||||
</section>
|
||||
<div v-if="isOwner" class="post-editor surface-card">
|
||||
<h3>{{ $t('blog.newPost') }}</h3>
|
||||
<form @submit.prevent="addPost">
|
||||
<input v-model="newPost.title" :placeholder="$t('blog.title')" required />
|
||||
<RichTextEditor v-model="newPost.content" :blog-id="blog.id" />
|
||||
<button class="btn" type="submit">{{ $t('blog.publish') }}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isOwner" class="post-editor">
|
||||
<h3>{{ $t('blog.newPost') }}</h3>
|
||||
<form @submit.prevent="addPost">
|
||||
<input v-model="newPost.title" :placeholder="$t('blog.title')" required />
|
||||
<RichTextEditor v-model="newPost.content" :blog-id="blog.id" />
|
||||
<button class="btn" type="submit">{{ $t('blog.publish') }}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -169,12 +178,109 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.blog-view {
|
||||
max-width: var(--content-max-width);
|
||||
margin: 0 auto;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.blog-layout {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.blog-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 20px;
|
||||
padding: 26px;
|
||||
}
|
||||
|
||||
.blog-description {
|
||||
margin: 0;
|
||||
max-width: 70ch;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.meta {
|
||||
margin-bottom: 10px;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.82rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.blog-content {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 2fr) minmax(280px, 0.95fr);
|
||||
gap: 18px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.posts,
|
||||
.post-editor {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.posts__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.posts__count {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.82rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.post + .post {
|
||||
margin-top: 18px;
|
||||
padding-top: 18px;
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.content {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.blog-view__state {
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.editbutton {
|
||||
border: 1px solid #000;
|
||||
background-color: #f9a22c;
|
||||
margin-bottom: 1em;
|
||||
border-radius: 3px;
|
||||
padding: 0.2em 0.5em;
|
||||
margin-bottom: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.blog-hero,
|
||||
.blog-content {
|
||||
grid-template-columns: 1fr;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.blog-hero {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.posts,
|
||||
.post-editor {
|
||||
padding: 18px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user