Refactor chat interface and enhance user experience
- Updated the ChatWindow component to provide clearer instructions and actions when no conversation is selected, improving user guidance. - Redesigned the MenuBar to display session timeout information more effectively. - Enhanced the SearchView component with a more user-friendly country selection using a Multiselect dropdown. - Improved the UserList component to display user age and gender, enhancing user profile visibility. - Updated various views (ChatView, FaqView, FeedbackView, PartnersView, RulesView, SafetyView) to include a consistent app branding link for better navigation. These changes collectively enhance the chat interface, improve user engagement, and streamline navigation across the application.
This commit is contained in:
@@ -1,7 +1,27 @@
|
||||
<template>
|
||||
<div class="chat-window">
|
||||
<div v-if="!chatStore.currentConversation" class="no-conversation">
|
||||
<p>Wähle einen Benutzer aus der Liste aus, um eine Unterhaltung zu starten.</p>
|
||||
<div class="empty-icon">C</div>
|
||||
<h2>Unterhaltung starten</h2>
|
||||
<p>Wähle eine Person aus der aktiven Liste oder suche gezielt nach jemandem.</p>
|
||||
<div class="empty-actions">
|
||||
<button type="button" @click="chatStore.setView('search')">Zur Suche</button>
|
||||
<button type="button" class="secondary" @click="chatStore.setView('history')">Verlauf ansehen</button>
|
||||
</div>
|
||||
<div class="empty-stats">
|
||||
<span>
|
||||
<strong>Sicherer Chat</strong>
|
||||
Privater Austausch
|
||||
</span>
|
||||
<span>
|
||||
<strong>{{ chatStore.users.length }} online</strong>
|
||||
Aktive Kontakte
|
||||
</span>
|
||||
<span>
|
||||
<strong>Profile</strong>
|
||||
Direkt erreichbar
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="messages-container">
|
||||
@@ -105,12 +125,97 @@ function formatTime(timestamp) {
|
||||
|
||||
<style scoped>
|
||||
.no-conversation {
|
||||
padding: 20px;
|
||||
min-height: 100%;
|
||||
padding: 60px 24px;
|
||||
text-align: center;
|
||||
color: #637067;
|
||||
border: 1px dashed #d7dfd9;
|
||||
border-radius: 12px;
|
||||
color: #4f5c54;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 74px;
|
||||
height: 74px;
|
||||
border-radius: 8px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: #ffffff;
|
||||
color: #1e6840;
|
||||
font-size: 24px;
|
||||
font-weight: 900;
|
||||
box-shadow: 0 18px 34px rgba(29, 45, 36, 0.08);
|
||||
}
|
||||
|
||||
.no-conversation h2 {
|
||||
margin: 24px 0 12px;
|
||||
color: #202720;
|
||||
font-size: 25px;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.no-conversation p {
|
||||
max-width: 430px;
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.empty-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
margin-top: 28px;
|
||||
}
|
||||
|
||||
.empty-actions button {
|
||||
min-height: 46px;
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
padding: 0 24px;
|
||||
background: #1f6e43;
|
||||
color: #ffffff;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.empty-actions button.secondary {
|
||||
background: #ebeeec;
|
||||
color: #2c5f40;
|
||||
}
|
||||
|
||||
.empty-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(120px, 1fr));
|
||||
gap: 12px;
|
||||
width: min(520px, 100%);
|
||||
margin-top: 48px;
|
||||
}
|
||||
|
||||
.empty-stats span {
|
||||
min-height: 58px;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
color: #707c73;
|
||||
font-size: 10px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.empty-stats strong {
|
||||
margin-bottom: 3px;
|
||||
color: #253027;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
@media (max-width: 620px) {
|
||||
.empty-stats {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.messages-container {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
<template>
|
||||
<div class="menu">
|
||||
<template v-if="chatStore.isLoggedIn">
|
||||
<span class="menu-info-text">{{ $t('menu_in_chat_for', [chatStore.currentConversation || '-']) }}</span>
|
||||
<span v-if="chatStore.remainingSecondsToTimeout > 0" class="menu-info-text">
|
||||
{{ $t('menu_timeout_in', [formatTime(chatStore.remainingSecondsToTimeout)]) }}
|
||||
</span>
|
||||
<button @click="handleLeave">{{ $t('menu_leave') }}</button>
|
||||
<button @click="handleSearch" :class="{ 'is-active': chatStore.currentView === 'search' }">
|
||||
{{ $t('menu_search') }}
|
||||
@@ -18,6 +14,9 @@
|
||||
<button @click="handleHistory" :class="{ 'is-active': chatStore.currentView === 'history' }">
|
||||
{{ $t('menu_history') }}
|
||||
</button>
|
||||
<span v-if="chatStore.remainingSecondsToTimeout > 0" class="menu-info-text">
|
||||
{{ formatTime(chatStore.remainingSecondsToTimeout) }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -21,11 +21,20 @@
|
||||
|
||||
<div class="form-row">
|
||||
<label>{{ $t('search_country') }}</label>
|
||||
<select v-model="selectedCountries" multiple>
|
||||
<option v-for="(code, name) in countries" :key="code" :value="name">
|
||||
{{ name }}
|
||||
</option>
|
||||
</select>
|
||||
<Multiselect
|
||||
v-model="selectedCountries"
|
||||
:options="countryOptions"
|
||||
mode="tags"
|
||||
:close-on-select="false"
|
||||
:searchable="true"
|
||||
:placeholder="$t('search_all')"
|
||||
track-by="value"
|
||||
label="label"
|
||||
value-prop="value"
|
||||
:hide-selected="false"
|
||||
:can-deselect="true"
|
||||
:create-option="false"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
@@ -33,7 +42,7 @@
|
||||
<Multiselect
|
||||
v-model="searchData.genders"
|
||||
:options="translatedGenderOptions"
|
||||
mode="multiple"
|
||||
mode="tags"
|
||||
:close-on-select="false"
|
||||
:searchable="true"
|
||||
:placeholder="$t('search_all')"
|
||||
@@ -102,38 +111,66 @@ const genderOptions = [
|
||||
|
||||
// Übersetzte Geschlechter-Optionen
|
||||
const translatedGenderOptions = computed(() => {
|
||||
return genderOptions.map(option => ({
|
||||
const ownGender = chatStore.gender;
|
||||
const preferredOrder = ownGender === 'M'
|
||||
? ['F', 'M', 'P', 'TF', 'TM']
|
||||
: ownGender === 'F'
|
||||
? ['M', 'F', 'P', 'TF', 'TM']
|
||||
: genderOptions.map(option => option.value);
|
||||
|
||||
const orderIndex = new Map(preferredOrder.map((value, index) => [value, index]));
|
||||
const sortedOptions = [...genderOptions].sort((a, b) => {
|
||||
return (orderIndex.get(a.value) ?? 999) - (orderIndex.get(b.value) ?? 999);
|
||||
});
|
||||
|
||||
return sortedOptions.map(option => ({
|
||||
value: option.value,
|
||||
label: t(option.label)
|
||||
}));
|
||||
});
|
||||
|
||||
// Übersetzte Länderliste (sortiert)
|
||||
// Übersetzte Länderliste mit stabilem Wert (englischer Ländername)
|
||||
const countries = computed(() => {
|
||||
const translated = {};
|
||||
const translations = countryTranslations[locale.value] || countryTranslations.en || {};
|
||||
const list = Object.entries(countriesRaw.value).map(([englishName, isoCode]) => ({
|
||||
label: translations[englishName] || englishName,
|
||||
value: englishName,
|
||||
isoCode
|
||||
}));
|
||||
|
||||
list.sort((a, b) => a.label.localeCompare(b.label, locale.value));
|
||||
return list;
|
||||
});
|
||||
|
||||
const countryOptions = computed(() => {
|
||||
const options = [...countries.value];
|
||||
const ownCountry = chatStore.country;
|
||||
if (!ownCountry) return options;
|
||||
|
||||
// Priorisiere das eigene Land anhand des stabilen Werts (englischer Ländername).
|
||||
// Fallback: vergleiche zusätzlich das übersetzte Label, falls der Wert bereits lokalisiert gespeichert wurde.
|
||||
const translations = countryTranslations[locale.value] || countryTranslations['en'] || {};
|
||||
|
||||
for (const [englishName, code] of Object.entries(countriesRaw.value)) {
|
||||
// Verwende Übersetzung falls vorhanden, sonst englischen Namen
|
||||
translated[translations[englishName] || englishName] = code;
|
||||
}
|
||||
|
||||
// Sortiere alphabetisch nach übersetztem Namen
|
||||
const sorted = {};
|
||||
Object.keys(translated).sort((a, b) => a.localeCompare(b, locale.value)).forEach(key => {
|
||||
sorted[key] = translated[key];
|
||||
});
|
||||
|
||||
return sorted;
|
||||
const ownCountryTranslated = translations[ownCountry] || ownCountry;
|
||||
const ownCountryIndex = options.findIndex(option => (
|
||||
option.value === ownCountry || option.label === ownCountry || option.label === ownCountryTranslated
|
||||
));
|
||||
if (ownCountryIndex <= 0) return options;
|
||||
|
||||
const [ownCountryOption] = options.splice(ownCountryIndex, 1);
|
||||
options.unshift(ownCountryOption);
|
||||
return options;
|
||||
});
|
||||
|
||||
// Verwende searchData direkt aus dem Store, damit die Daten beim View-Wechsel erhalten bleiben
|
||||
const searchData = chatStore.searchData;
|
||||
|
||||
const selectedCountries = computed({
|
||||
get: () => chatStore.searchData.selectedCountries || [],
|
||||
get: () => chatStore.searchData.selectedCountries?.length
|
||||
? chatStore.searchData.selectedCountries
|
||||
: (chatStore.searchData.selectedCountriesEnglish || []),
|
||||
set: (value) => {
|
||||
chatStore.searchData.selectedCountries = value;
|
||||
chatStore.searchData.selectedCountriesEnglish = value;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -160,17 +197,7 @@ function handleSearch() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Konvertiere übersetzte Ländernamen zurück zu englischen Namen
|
||||
const translations = countryTranslations[locale.value] || countryTranslations['en'] || {};
|
||||
const englishCountryNames = (chatStore.searchData.selectedCountries || []).map(translatedName => {
|
||||
// Suche den englischen Namen
|
||||
for (const [englishName, translated] of Object.entries(translations)) {
|
||||
if (translated === translatedName) {
|
||||
return englishName;
|
||||
}
|
||||
}
|
||||
return translatedName; // Fallback: verwende den Namen wie er ist
|
||||
});
|
||||
const englishCountryNames = chatStore.searchData.selectedCountries || [];
|
||||
|
||||
// Konvertiere Multiselect-Werte zu Array von Strings (falls Objekte)
|
||||
const genderValues = Array.isArray(chatStore.searchData.genders)
|
||||
@@ -185,7 +212,6 @@ function handleSearch() {
|
||||
genders: genderValues.length > 0 ? genderValues : null
|
||||
};
|
||||
|
||||
// Speichere auch die englischen Länder-Namen im Store für spätere Aktualisierungen
|
||||
chatStore.searchData.selectedCountriesEnglish = englishCountryNames.length > 0 ? englishCountryNames : [];
|
||||
|
||||
chatStore.userSearch(searchPayload);
|
||||
@@ -269,64 +295,54 @@ function selectUser(userName) {
|
||||
}
|
||||
|
||||
:deep(.multiselect) {
|
||||
min-height: auto;
|
||||
border: 1px solid var(--color-border);
|
||||
min-height: 38px;
|
||||
border: 0;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface);
|
||||
box-shadow: inset 0 0 0 1px var(--color-border);
|
||||
}
|
||||
|
||||
:deep(.multiselect-wrapper),
|
||||
:deep(.multiselect-tags-search-wrapper),
|
||||
:deep(.multiselect-tags-search-copy) {
|
||||
border: 0 !important;
|
||||
box-shadow: none !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect-input-wrapper) {
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
padding: 0.25em;
|
||||
min-height: 2em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:deep(.multiselect-input-wrapper > *) {
|
||||
flex-shrink: 0;
|
||||
padding: 4px 6px;
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
:deep(.multiselect-tags) {
|
||||
min-height: 2em;
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
gap: 0.25em;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
min-height: 24px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.multiselect.is-open .multiselect-tags) {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect:not(.is-open) .multiselect-tags) {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect-tag) {
|
||||
background: #3d8654;
|
||||
color: white;
|
||||
padding: 0.25em 0.5em;
|
||||
padding: 3px 8px;
|
||||
margin: 0;
|
||||
border-radius: 3px;
|
||||
display: inline-flex !important;
|
||||
border-radius: 999px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
font-size: 0.9em;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
:deep(.multiselect-tag i) {
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
cursor: pointer;
|
||||
margin-left: 0.25em;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
:deep(.multiselect-tag i:hover) {
|
||||
@@ -335,75 +351,38 @@ function selectUser(userName) {
|
||||
|
||||
:deep(.multiselect-placeholder) {
|
||||
color: #8a948e;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
:deep(.multiselect-single-label) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect-multiple-label) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect-tags-text) {
|
||||
display: none !important;
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.multiselect-search) {
|
||||
display: block !important;
|
||||
flex: 0 0 auto;
|
||||
min-width: 20px;
|
||||
max-width: 50px;
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:deep(.multiselect-tags-search) {
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
gap: 0.25em;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
:deep(.multiselect-tags-search .multiselect-tag) {
|
||||
background: #3d8654;
|
||||
color: white;
|
||||
padding: 0.25em 0.5em;
|
||||
margin: 0;
|
||||
border-radius: 3px;
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
font-size: 0.9em;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
min-width: 80px;
|
||||
font-size: 13px;
|
||||
color: #18201b;
|
||||
border: 0 !important;
|
||||
box-shadow: none !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect-input) {
|
||||
flex: 0 0 auto;
|
||||
min-width: 50px;
|
||||
min-height: 22px;
|
||||
border: 0 !important;
|
||||
box-shadow: none !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect-tags-search) {
|
||||
border: 0 !important;
|
||||
box-shadow: none !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect.is-active) {
|
||||
border-color: #3d8654;
|
||||
box-shadow: 0 0 0 3px rgba(61, 134, 84, 0.12);
|
||||
}
|
||||
|
||||
:deep(.multiselect.is-active .multiselect-tags) {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect:not(.is-active) .multiselect-tags) {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect-single) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:deep(.multiselect-multiple) {
|
||||
display: block !important;
|
||||
box-shadow:
|
||||
inset 0 0 0 1px #3d8654,
|
||||
0 0 0 3px rgba(61, 134, 84, 0.12);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,17 +15,14 @@
|
||||
]"
|
||||
@click="selectUser(user.userName)"
|
||||
>
|
||||
<img
|
||||
v-if="user.isoCountryCode"
|
||||
:src="`/static/flags/${user.isoCountryCode}.png`"
|
||||
:alt="user.country"
|
||||
class="flag-icon"
|
||||
/>
|
||||
<span class="user-avatar" :data-initial="user.userName.charAt(0).toUpperCase()">
|
||||
<span class="user-status" aria-hidden="true"></span>
|
||||
</span>
|
||||
<span class="user-main">
|
||||
<span class="user-name">{{ user.userName }}</span>
|
||||
<span class="user-country">{{ user.isoCountryCode || '' }}</span>
|
||||
<span class="user-country">{{ user.age }} · {{ user.gender }}</span>
|
||||
</span>
|
||||
<span class="user-meta">{{ user.age }} · {{ user.gender }}</span>
|
||||
<span class="user-meta">{{ user.isoCountryCode || '' }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
--color-purple: #8b60af;
|
||||
--color-cyan: #5fa2bf;
|
||||
--radius-sm: 8px;
|
||||
--radius-md: 10px;
|
||||
--radius-lg: 12px;
|
||||
--radius-md: 8px;
|
||||
--radius-lg: 8px;
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
@@ -34,6 +34,213 @@
|
||||
--sidebar-width: 188px;
|
||||
}
|
||||
|
||||
.chat-container-auth {
|
||||
flex-direction: column;
|
||||
background: #f7f9f7;
|
||||
}
|
||||
|
||||
.auth-main-layout {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-sidebar {
|
||||
width: 224px;
|
||||
flex-shrink: 0;
|
||||
padding: 28px 14px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #e8f7ef;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.sidebar-brand {
|
||||
padding: 0 14px 34px;
|
||||
color: #173a27;
|
||||
}
|
||||
|
||||
.sidebar-brand strong {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
line-height: 1.15;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sidebar-brand span {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
color: #4e9872;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 9px;
|
||||
}
|
||||
|
||||
.sidebar-nav button {
|
||||
min-height: 42px;
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
padding: 0 12px;
|
||||
display: grid;
|
||||
grid-template-columns: 24px minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background: transparent;
|
||||
color: #54836d;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.sidebar-nav button:hover,
|
||||
.sidebar-nav button.is-active {
|
||||
background: #a9efcc;
|
||||
color: #164d2c;
|
||||
}
|
||||
|
||||
.sidebar-nav button.has-unread {
|
||||
color: #9f4d4d;
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 6px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: currentColor;
|
||||
background: rgba(255, 255, 255, 0.42);
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sidebar-badge {
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
padding: 0 6px;
|
||||
border-radius: 8px;
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
background: #fff0f0;
|
||||
color: #9f4d4d;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.sidebar-profile {
|
||||
margin-top: auto;
|
||||
min-height: 64px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background: #c9f6dc;
|
||||
color: #173a27;
|
||||
}
|
||||
|
||||
.profile-avatar,
|
||||
.icon-button {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 8px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: #2f7047;
|
||||
color: #ffffff;
|
||||
font-weight: 800;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.sidebar-profile span:last-child {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.sidebar-profile strong,
|
||||
.sidebar-profile small {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sidebar-profile strong {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.sidebar-profile small {
|
||||
margin-top: 2px;
|
||||
color: #5f7f6e;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.app-workspace {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.workspace-header {
|
||||
height: 64px;
|
||||
flex-shrink: 0;
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(260px, 1fr) auto auto;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 0 28px;
|
||||
background: #f7fbf8;
|
||||
border-bottom: 1px solid #eef3ef;
|
||||
}
|
||||
|
||||
.workspace-header h1 {
|
||||
margin: 0;
|
||||
color: #1d3f2b;
|
||||
font-size: 21px;
|
||||
line-height: 1;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.workspace-search {
|
||||
width: min(280px, 24vw);
|
||||
height: 40px;
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
padding: 0 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background: #e3f8ed;
|
||||
color: #6e9280;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.workspace-search span {
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
color: #1e6840;
|
||||
}
|
||||
|
||||
.workspace-search strong {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
border: 0;
|
||||
background: #ecf7f1;
|
||||
color: #1e6840;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -227,6 +434,13 @@ a {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Content-Seiten (FAQ/Regeln/Sicherheit/Feedback) sollen den Footer nach unten drücken. */
|
||||
.chat-container > main {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.horizontal-box-app {
|
||||
gap: 14px;
|
||||
padding: 14px;
|
||||
@@ -653,3 +867,404 @@ a {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-container-auth .menu {
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
justify-content: center;
|
||||
gap: 22px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.chat-container-auth .menu button {
|
||||
height: 64px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
color: #88a095;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chat-container-auth .menu button:hover {
|
||||
background: transparent;
|
||||
color: #1f6e43;
|
||||
}
|
||||
|
||||
.chat-container-auth .menu button.is-active::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 12px;
|
||||
height: 2px;
|
||||
background: #1f6e43;
|
||||
}
|
||||
|
||||
.chat-container-auth .menu button.has-unread {
|
||||
color: #9f4d4d;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.chat-container-auth .menu-info-text {
|
||||
min-height: 24px;
|
||||
padding: 0 8px;
|
||||
border: 0;
|
||||
background: #eff6f2;
|
||||
color: #62806f;
|
||||
}
|
||||
|
||||
.chat-container-auth .horizontal-box-app {
|
||||
padding: 14px 26px 24px;
|
||||
gap: 24px;
|
||||
background: linear-gradient(90deg, #fbfbfb 0%, #f8faf8 56%, #f2f7f3 100%);
|
||||
}
|
||||
|
||||
.chat-container-auth .user-list {
|
||||
width: 280px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.chat-container-auth .user-list h3 {
|
||||
min-height: 38px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #1c633c;
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.chat-container-auth .user-list-scroll {
|
||||
gap: 10px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.chat-container-auth .user-item {
|
||||
min-height: 64px;
|
||||
padding: 10px 12px;
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
grid-template-columns: 42px minmax(0, 1fr) auto;
|
||||
gap: 12px;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.chat-container-auth .user-item:hover,
|
||||
.chat-container-auth .user-item.is-active {
|
||||
background: #ffffff;
|
||||
box-shadow: 0 12px 28px rgba(25, 45, 34, 0.06);
|
||||
}
|
||||
|
||||
.chat-container-auth .user-item.gender-M,
|
||||
.chat-container-auth .user-item.gender-F,
|
||||
.chat-container-auth .user-item.gender-P,
|
||||
.chat-container-auth .user-item.gender-TM,
|
||||
.chat-container-auth .user-item.gender-TF {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 8px;
|
||||
position: relative;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: linear-gradient(145deg, #1d2b24 0%, #43544a 100%);
|
||||
color: #fff;
|
||||
font-weight: 800;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.user-avatar::before {
|
||||
content: attr(data-initial);
|
||||
}
|
||||
|
||||
.user-status {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
border-radius: 8px;
|
||||
position: absolute;
|
||||
right: -1px;
|
||||
bottom: 2px;
|
||||
background: #32c46b;
|
||||
border: 2px solid #ffffff;
|
||||
}
|
||||
|
||||
.chat-container-auth .user-name {
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.chat-container-auth .user-country {
|
||||
display: block;
|
||||
margin-top: 3px;
|
||||
font-size: 11px;
|
||||
color: #616f66;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.chat-container-auth .user-main {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chat-container-auth .user-meta {
|
||||
color: #88978e;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.chat-container-auth .content {
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
background:
|
||||
radial-gradient(circle at 15% 100%, rgba(79, 152, 114, 0.15), transparent 24%),
|
||||
linear-gradient(120deg, #ffffff 0%, #f9faf9 52%, #f3f5f3 100%);
|
||||
box-shadow: 0 26px 70px rgba(29, 45, 36, 0.08);
|
||||
}
|
||||
|
||||
.chat-container-auth .chat-window {
|
||||
background: transparent;
|
||||
padding: 28px;
|
||||
}
|
||||
|
||||
.chat-container-auth .chat-input-container {
|
||||
border-top: 1px solid #edf2ee;
|
||||
background: rgba(255, 255, 255, 0.82);
|
||||
}
|
||||
|
||||
.chat-container-auth .imprint-container {
|
||||
height: 48px;
|
||||
min-height: 48px;
|
||||
border-top: 1px solid #eef3ef;
|
||||
background: #ffffff;
|
||||
color: #98a49d;
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.chat-container-auth {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.app-sidebar {
|
||||
width: 100%;
|
||||
min-height: 92px;
|
||||
padding: 12px;
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.sidebar-brand {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
flex-direction: row;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.sidebar-nav button {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.workspace-header {
|
||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
.workspace-search {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.app-sidebar {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.sidebar-profile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.workspace-header {
|
||||
height: auto;
|
||||
min-height: 58px;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.workspace-header .menu {
|
||||
grid-column: 1 / -1;
|
||||
justify-content: flex-start;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.chat-container-auth .horizontal-box-app {
|
||||
padding: 10px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.chat-container-auth .user-list {
|
||||
max-height: 190px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Authenticated shell: keep these overrides at the end so the base app shell cannot override them. */
|
||||
.chat-container.chat-container-auth {
|
||||
flex-direction: column;
|
||||
background: #edf7f1;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .app-sidebar {
|
||||
width: 286px;
|
||||
padding: 30px 16px 14px;
|
||||
background: linear-gradient(180deg, #d6f4e7 0%, #d0efe2 100%);
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .sidebar-brand {
|
||||
color: #143d27;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .sidebar-brand span {
|
||||
color: #3f8c65;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .sidebar-nav button {
|
||||
min-height: 44px;
|
||||
border-radius: 10px;
|
||||
color: #5e8a73;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .sidebar-nav button:hover,
|
||||
.chat-container.chat-container-auth .sidebar-nav button.is-active {
|
||||
background: #a6efc7;
|
||||
color: #114d2c;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .sidebar-profile {
|
||||
border-radius: 10px;
|
||||
background: #c4f5d9;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .app-workspace {
|
||||
background: #f8faf8;
|
||||
border-top: 1px solid #d6ddd8;
|
||||
border-right: 1px solid #d6ddd8;
|
||||
border-bottom: 1px solid #d6ddd8;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .workspace-header {
|
||||
min-height: 82px;
|
||||
padding: 0 24px;
|
||||
background: linear-gradient(180deg, #dcf5ea 0%, #d7f1e6 100%);
|
||||
border-bottom: 1px solid #cfd8d2;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .workspace-header h1 {
|
||||
color: #183d27;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .workspace-search,
|
||||
.chat-container.chat-container-auth .icon-button {
|
||||
background: #cbeee0;
|
||||
color: #165f37;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .horizontal-box-app {
|
||||
gap: 18px;
|
||||
padding: 12px 14px 16px;
|
||||
background: linear-gradient(90deg, #fbfbfa 0%, #f6f8f6 54%, #eaf4ee 100%);
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .user-list {
|
||||
width: 318px;
|
||||
padding: 14px;
|
||||
border: 1px solid #e1e8e3;
|
||||
border-radius: 12px;
|
||||
background: #ffffff;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .content {
|
||||
border-radius: 34px;
|
||||
background:
|
||||
radial-gradient(circle at 17% 100%, rgba(50, 125, 86, 0.24), transparent 28%),
|
||||
linear-gradient(120deg, #f7f6f4 0%, #f1f0ed 54%, #e8f0eb 100%);
|
||||
box-shadow: 0 28px 80px rgba(22, 40, 30, 0.08);
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .menu button {
|
||||
color: #527a66;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .menu button:hover,
|
||||
.chat-container.chat-container-auth .menu button.is-active {
|
||||
color: #18683d;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .menu button.is-active::after {
|
||||
background: #18683d;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .user-list h3 {
|
||||
font-size: 17px;
|
||||
line-height: 1.2;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0;
|
||||
color: #17643c;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .user-item {
|
||||
min-height: 64px;
|
||||
border: 1px solid #edf2ee;
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .user-item:hover,
|
||||
.chat-container.chat-container-auth .user-item.is-active {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .chat-input-container {
|
||||
border-top: 1px solid #d9e5de;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .chat-input-container button {
|
||||
background: #1f6f43;
|
||||
border-color: #1b633b;
|
||||
}
|
||||
|
||||
.chat-container.chat-container-auth .imprint-container {
|
||||
min-height: 58px;
|
||||
border-top: 1px solid #d0d6d2;
|
||||
background: #f0f2f1;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.chat-container.chat-container-auth {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.auth-main-layout {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +1,141 @@
|
||||
<template>
|
||||
<div class="chat-container">
|
||||
<header class="header">
|
||||
<div class="app-brand">
|
||||
<span class="app-brand-mark">S</span>
|
||||
<div class="app-brand-copy">
|
||||
<span class="app-brand-eyebrow">SingleChat</span>
|
||||
<h1>Chat</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="chatStore.isLoggedIn" class="header-status">
|
||||
<span class="header-status-chip">{{ chatStore.userName }}</span>
|
||||
<span v-if="chatStore.isoCountryCode" class="header-status-chip">{{ chatStore.isoCountryCode }}</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<MenuBar v-if="chatStore.isLoggedIn" />
|
||||
|
||||
<div class="horizontal-box" :class="{ 'horizontal-box-login': !chatStore.isLoggedIn, 'horizontal-box-app': chatStore.isLoggedIn }">
|
||||
<UserList v-if="chatStore.isLoggedIn" />
|
||||
|
||||
<div class="content">
|
||||
<div v-if="!chatStore.isLoggedIn" class="login-screen">
|
||||
<LoginForm />
|
||||
</div>
|
||||
|
||||
<div v-else class="main-content-wrapper">
|
||||
<div v-if="chatStore.errorMessage" class="error-message">
|
||||
{{ chatStore.errorMessage }}
|
||||
<div class="chat-container" :class="{ 'chat-container-auth': chatStore.isLoggedIn }">
|
||||
<template v-if="chatStore.isLoggedIn">
|
||||
<div class="auth-main-layout">
|
||||
<aside class="app-sidebar">
|
||||
<div class="sidebar-brand">
|
||||
<strong>SingleChat</strong>
|
||||
<span>Online Chat</span>
|
||||
</div>
|
||||
<div v-if="chatStore.commandTable" class="command-table-container">
|
||||
<div class="command-table-header">
|
||||
<strong>{{ chatStore.commandTable.title }}</strong>
|
||||
<button class="command-table-close" @click="chatStore.clearCommandTable()">Schließen</button>
|
||||
</div>
|
||||
<div class="command-table-scroll">
|
||||
<table class="command-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(column, idx) in chatStore.commandTable.columns" :key="`head-${idx}`">
|
||||
{{ column }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIdx) in chatStore.commandTable.rows" :key="`row-${rowIdx}`">
|
||||
<td v-for="(cell, cellIdx) in row" :key="`cell-${rowIdx}-${cellIdx}`">
|
||||
{{ cell }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav" aria-label="Hauptnavigation">
|
||||
<button
|
||||
type="button"
|
||||
:class="{ 'is-active': chatStore.currentView === 'chat' }"
|
||||
@click="goLobby"
|
||||
>
|
||||
<span class="nav-icon" aria-hidden="true">🏠</span>
|
||||
Lobby
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="{ 'is-active': chatStore.currentView === 'inbox', 'has-unread': chatStore.unreadChatsCount > 0 }"
|
||||
@click="chatStore.setView('inbox')"
|
||||
>
|
||||
<span class="nav-icon" aria-hidden="true">📥</span>
|
||||
{{ $t('menu_inbox') }}
|
||||
<span v-if="chatStore.unreadChatsCount > 0" class="sidebar-badge">{{ chatStore.unreadChatsCount }}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="{ 'is-active': chatStore.currentView === 'history' }"
|
||||
@click="chatStore.setView('history')"
|
||||
>
|
||||
<span class="nav-icon" aria-hidden="true">🕘</span>
|
||||
{{ $t('menu_history') }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="{ 'is-active': chatStore.currentView === 'search' }"
|
||||
@click="chatStore.setView('search')"
|
||||
>
|
||||
<span class="nav-icon" aria-hidden="true">🔎</span>
|
||||
{{ $t('menu_search') }}
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-profile">
|
||||
<span class="profile-avatar">{{ userInitials }}</span>
|
||||
<span>
|
||||
<strong>{{ chatStore.userName }}</strong>
|
||||
<small>{{ chatStore.country || 'SingleChat Member' }}</small>
|
||||
</span>
|
||||
</div>
|
||||
<SearchView v-if="chatStore.currentView === 'search'" />
|
||||
<InboxView v-else-if="chatStore.currentView === 'inbox'" />
|
||||
<HistoryView v-else-if="chatStore.currentView === 'history'" />
|
||||
<div v-else class="chat-content">
|
||||
<div v-if="chatStore.currentConversation && currentUserInfo" class="chat-header">
|
||||
<span :class="['chat-header-accent', 'chat-header-accent-' + currentUserInfo.gender]"></span>
|
||||
<div class="chat-header-main">
|
||||
<h2>{{ chatStore.currentConversation }}</h2>
|
||||
<div class="chat-header-info">
|
||||
<span v-if="currentUserInfo">{{ currentUserInfo.country }}</span>
|
||||
<span v-if="currentUserInfo">{{ currentUserInfo.age }} · {{ currentUserInfo.gender }}</span>
|
||||
</aside>
|
||||
|
||||
<section class="app-workspace">
|
||||
<header class="workspace-header">
|
||||
<h1>{{ pageTitle }}</h1>
|
||||
<MenuBar />
|
||||
<button type="button" class="icon-button" :title="chatStore.userName">{{ userInitials }}</button>
|
||||
</header>
|
||||
|
||||
<div class="horizontal-box horizontal-box-app">
|
||||
<UserList />
|
||||
|
||||
<div class="content">
|
||||
<div class="main-content-wrapper">
|
||||
<div v-if="chatStore.errorMessage" class="error-message">
|
||||
{{ chatStore.errorMessage }}
|
||||
</div>
|
||||
<div v-if="chatStore.commandTable" class="command-table-container">
|
||||
<div class="command-table-header">
|
||||
<strong>{{ chatStore.commandTable.title }}</strong>
|
||||
<button class="command-table-close" @click="chatStore.clearCommandTable()">Schließen</button>
|
||||
</div>
|
||||
<div class="command-table-scroll">
|
||||
<table class="command-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(column, idx) in chatStore.commandTable.columns" :key="`head-${idx}`">
|
||||
{{ column }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIdx) in chatStore.commandTable.rows" :key="`row-${rowIdx}`">
|
||||
<td v-for="(cell, cellIdx) in row" :key="`cell-${rowIdx}-${cellIdx}`">
|
||||
{{ cell }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<SearchView v-if="chatStore.currentView === 'search'" />
|
||||
<InboxView v-else-if="chatStore.currentView === 'inbox'" />
|
||||
<HistoryView v-else-if="chatStore.currentView === 'history'" />
|
||||
<div v-else class="chat-content">
|
||||
<div v-if="chatStore.currentConversation && currentUserInfo" class="chat-header">
|
||||
<span :class="['chat-header-accent', 'chat-header-accent-' + currentUserInfo.gender]"></span>
|
||||
<div class="chat-header-main">
|
||||
<h2>{{ chatStore.currentConversation }}</h2>
|
||||
<div class="chat-header-info">
|
||||
<span v-if="currentUserInfo">{{ currentUserInfo.country }}</span>
|
||||
<span v-if="currentUserInfo">{{ currentUserInfo.age }} · {{ currentUserInfo.gender }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ChatWindow />
|
||||
</div>
|
||||
<ChatInput />
|
||||
</div>
|
||||
</div>
|
||||
<ChatWindow />
|
||||
</div>
|
||||
<ChatInput />
|
||||
</section>
|
||||
</div>
|
||||
<ImprintContainer />
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<header class="header">
|
||||
<div class="app-brand">
|
||||
<span class="app-brand-mark">S</span>
|
||||
<div class="app-brand-copy">
|
||||
<span class="app-brand-eyebrow">SingleChat</span>
|
||||
<h1>Chat</h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="horizontal-box horizontal-box-login">
|
||||
<div class="content login-content-shell">
|
||||
<div class="login-screen">
|
||||
<LoginForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ImprintContainer />
|
||||
<ImprintContainer />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -92,6 +154,29 @@ import ImprintContainer from '../components/ImprintContainer.vue';
|
||||
|
||||
const chatStore = useChatStore();
|
||||
|
||||
const userInitials = computed(() => {
|
||||
return (chatStore.userName || 'SC')
|
||||
.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.slice(0, 2)
|
||||
.map(part => part.charAt(0).toUpperCase())
|
||||
.join('') || 'SC';
|
||||
});
|
||||
|
||||
const pageTitle = computed(() => {
|
||||
if (chatStore.currentView === 'search') return 'Suchen';
|
||||
if (chatStore.currentView === 'inbox') return 'Posteingang';
|
||||
if (chatStore.currentView === 'history') return 'Verlauf';
|
||||
if (chatStore.currentConversation) return chatStore.currentConversation;
|
||||
return 'Lobby';
|
||||
});
|
||||
|
||||
function goLobby() {
|
||||
chatStore.currentConversation = null;
|
||||
chatStore.messages = [];
|
||||
chatStore.setView('chat');
|
||||
}
|
||||
|
||||
const currentUserInfo = computed(() => {
|
||||
if (!chatStore.currentConversation) return null;
|
||||
return chatStore.users.find(u => u.userName === chatStore.currentConversation);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="chat-container">
|
||||
<header class="header">
|
||||
<div class="app-brand">
|
||||
<router-link to="/" class="app-brand app-brand-link">
|
||||
<span class="app-brand-mark">S</span>
|
||||
<div class="app-brand-copy">
|
||||
<span class="app-brand-eyebrow">SingleChat</span>
|
||||
<h1>FAQ</h1>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
<HeaderAdBanner />
|
||||
</header>
|
||||
|
||||
@@ -85,5 +85,9 @@ import ImprintContainer from '../components/ImprintContainer.vue';
|
||||
.content-page a {
|
||||
color: #245c3a;
|
||||
}
|
||||
|
||||
.app-brand-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="chat-container">
|
||||
<header class="header">
|
||||
<div class="app-brand">
|
||||
<router-link to="/" class="app-brand app-brand-link">
|
||||
<span class="app-brand-mark">S</span>
|
||||
<div class="app-brand-copy">
|
||||
<span class="app-brand-eyebrow">SingleChat</span>
|
||||
<h1>Feedback</h1>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
<HeaderAdBanner />
|
||||
</header>
|
||||
|
||||
@@ -69,4 +69,8 @@ import ImprintContainer from '../components/ImprintContainer.vue';
|
||||
color: #344038;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.app-brand-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="chat-container">
|
||||
<header class="header">
|
||||
<div class="app-brand">
|
||||
<router-link to="/" class="app-brand app-brand-link">
|
||||
<span class="app-brand-mark">S</span>
|
||||
<div class="app-brand-copy">
|
||||
<span class="app-brand-eyebrow">SingleChat</span>
|
||||
<h1>Partner</h1>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
<HeaderAdBanner />
|
||||
</header>
|
||||
|
||||
@@ -102,4 +102,8 @@ onMounted(async () => {
|
||||
font-size: 12px;
|
||||
color: #637067;
|
||||
}
|
||||
|
||||
.app-brand-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="chat-container">
|
||||
<header class="header">
|
||||
<div class="app-brand">
|
||||
<router-link to="/" class="app-brand app-brand-link">
|
||||
<span class="app-brand-mark">S</span>
|
||||
<div class="app-brand-copy">
|
||||
<span class="app-brand-eyebrow">SingleChat</span>
|
||||
<h1>Regeln</h1>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
<HeaderAdBanner />
|
||||
</header>
|
||||
|
||||
@@ -80,5 +80,9 @@ import ImprintContainer from '../components/ImprintContainer.vue';
|
||||
margin: 18px 0 6px;
|
||||
color: #18201b;
|
||||
}
|
||||
|
||||
.app-brand-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="chat-container">
|
||||
<header class="header">
|
||||
<div class="app-brand">
|
||||
<router-link to="/" class="app-brand app-brand-link">
|
||||
<span class="app-brand-mark">S</span>
|
||||
<div class="app-brand-copy">
|
||||
<span class="app-brand-eyebrow">SingleChat</span>
|
||||
<h1>Sicherheit</h1>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
<HeaderAdBanner />
|
||||
</header>
|
||||
|
||||
@@ -72,5 +72,9 @@ import ImprintContainer from '../components/ImprintContainer.vue';
|
||||
.content-page a {
|
||||
color: #245c3a;
|
||||
}
|
||||
|
||||
.app-brand-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user