Enhance usability and localization across components: Update USABILITY_CONCEPT.md with new focus areas, improve user feedback in AppFooter and FamilyView components, and refine text in various UI elements for better clarity and consistency. Replace console logs with user-friendly messages, correct German translations, and streamline interaction logic in multiple components.
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { showInfo } from '@/utils/feedback.js';
|
||||
|
||||
export default {
|
||||
name: 'AppFooter',
|
||||
@@ -71,10 +72,10 @@ export default {
|
||||
},
|
||||
// Daemon WebSocket deaktiviert - diese Funktionen sind nicht mehr verfügbar
|
||||
async showFalukantDaemonStatus() {
|
||||
console.log('⚠️ Daemon WebSocket deaktiviert - Status nicht verfügbar');
|
||||
showInfo(this, 'Der Systemstatus ist in dieser Ansicht derzeit nicht direkt verfügbar.');
|
||||
},
|
||||
handleDaemonMessage(event) {
|
||||
console.log('⚠️ Daemon WebSocket deaktiviert - keine Nachrichten verarbeitet');
|
||||
handleDaemonMessage() {
|
||||
// Status-Events werden hier bewusst nicht verarbeitet.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
class="app-section-bar__back"
|
||||
@click="navigateBack"
|
||||
>
|
||||
Zurueck
|
||||
Zurück
|
||||
</button>
|
||||
</section>
|
||||
</template>
|
||||
@@ -25,13 +25,13 @@ const SECTION_LABELS = [
|
||||
{ test: (path) => path.startsWith('/settings'), label: 'Einstellungen' },
|
||||
{ test: (path) => path.startsWith('/admin'), label: 'Administration' },
|
||||
{ test: (path) => path.startsWith('/minigames'), label: 'Minispiele' },
|
||||
{ test: (path) => path.startsWith('/personal'), label: 'Persoenlich' },
|
||||
{ test: (path) => path.startsWith('/personal'), label: 'Persönlich' },
|
||||
{ test: (path) => path.startsWith('/blogs'), label: 'Blog' }
|
||||
];
|
||||
|
||||
const TITLE_MAP = {
|
||||
Friends: 'Freunde',
|
||||
Guestbook: 'Gaestebuch',
|
||||
Guestbook: 'Gästebuch',
|
||||
'Search users': 'Suche',
|
||||
Gallery: 'Galerie',
|
||||
Forum: 'Forum',
|
||||
@@ -46,7 +46,7 @@ const TITLE_MAP = {
|
||||
VocabCourse: 'Kurs',
|
||||
VocabLesson: 'Lektion',
|
||||
FalukantCreate: 'Charakter erstellen',
|
||||
FalukantOverview: 'Uebersicht',
|
||||
FalukantOverview: 'Übersicht',
|
||||
BranchView: 'Niederlassung',
|
||||
MoneyHistoryView: 'Geldverlauf',
|
||||
FalukantFamily: 'Familie',
|
||||
@@ -60,9 +60,9 @@ const TITLE_MAP = {
|
||||
HealthView: 'Gesundheit',
|
||||
PoliticsView: 'Politik',
|
||||
UndergroundView: 'Untergrund',
|
||||
'Personal settings': 'Persoenliche Daten',
|
||||
'Personal settings': 'Persönliche Daten',
|
||||
'View settings': 'Ansicht',
|
||||
'Sexuality settings': 'Sexualitaet',
|
||||
'Sexuality settings': 'Sexualität',
|
||||
'Flirt settings': 'Flirt',
|
||||
'Account settings': 'Account',
|
||||
Interests: 'Interessen',
|
||||
@@ -132,11 +132,19 @@ export default {
|
||||
return '/admin/users';
|
||||
}
|
||||
|
||||
if (window.history.length > 1) {
|
||||
return '__history_back__';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
navigateBack() {
|
||||
if (this.backTarget === '__history_back__') {
|
||||
this.$router.back();
|
||||
return;
|
||||
}
|
||||
if (this.backTarget) {
|
||||
this.$router.push(this.backTarget);
|
||||
}
|
||||
|
||||
@@ -17,23 +17,33 @@ import { getApiBaseURL } from '@/utils/axios.js';
|
||||
/** Backend-Route: GET /api/models/3d/falukant/characters/:filename (Proxy mit Draco-Optimierung) */
|
||||
const MODELS_API_PATH = '/api/models/3d/falukant/characters';
|
||||
let threeRuntimePromise = null;
|
||||
let threeLoadersPromise = null;
|
||||
let threeModelRuntimePromise = null;
|
||||
|
||||
async function loadThreeRuntime() {
|
||||
if (!threeRuntimePromise) {
|
||||
threeRuntimePromise = Promise.all([
|
||||
import('three'),
|
||||
import('three/addons/loaders/GLTFLoader.js'),
|
||||
import('three/addons/loaders/DRACOLoader.js')
|
||||
]).then(([THREE, { GLTFLoader }, { DRACOLoader }]) => ({
|
||||
THREE,
|
||||
GLTFLoader,
|
||||
DRACOLoader
|
||||
}));
|
||||
threeRuntimePromise = import('@/utils/threeRuntime.js');
|
||||
}
|
||||
|
||||
return threeRuntimePromise;
|
||||
}
|
||||
|
||||
async function loadThreeLoaders() {
|
||||
if (!threeLoadersPromise) {
|
||||
threeLoadersPromise = import('@/utils/threeLoaders.js');
|
||||
}
|
||||
|
||||
return threeLoadersPromise;
|
||||
}
|
||||
|
||||
async function loadThreeModelRuntime() {
|
||||
if (!threeModelRuntimePromise) {
|
||||
threeModelRuntimePromise = import('@/utils/threeModelRuntime.js');
|
||||
}
|
||||
|
||||
return threeModelRuntimePromise;
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'Character3D',
|
||||
props: {
|
||||
@@ -65,7 +75,9 @@ export default {
|
||||
clock: null,
|
||||
baseYPosition: 0,
|
||||
showFallback: false,
|
||||
threeRuntime: null
|
||||
threeRuntime: null,
|
||||
threeLoaders: null,
|
||||
threeModelRuntime: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -149,49 +161,65 @@ export default {
|
||||
return this.threeRuntime;
|
||||
},
|
||||
|
||||
async ensureThreeLoaders() {
|
||||
if (!this.threeLoaders) {
|
||||
this.threeLoaders = markRaw(await loadThreeLoaders());
|
||||
}
|
||||
|
||||
return this.threeLoaders;
|
||||
},
|
||||
|
||||
async ensureThreeModelRuntime() {
|
||||
if (!this.threeModelRuntime) {
|
||||
this.threeModelRuntime = markRaw(await loadThreeModelRuntime());
|
||||
}
|
||||
|
||||
return this.threeModelRuntime;
|
||||
},
|
||||
|
||||
async init3D() {
|
||||
const container = this.$refs.container;
|
||||
if (!container) return;
|
||||
this.showFallback = false;
|
||||
const { THREE } = await this.ensureThreeRuntime();
|
||||
this.clock = markRaw(new THREE.Clock());
|
||||
const runtime = await this.ensureThreeRuntime();
|
||||
this.clock = markRaw(new runtime.Clock());
|
||||
|
||||
// Scene erstellen - markRaw verwenden, um Vue's Reactivity zu vermeiden
|
||||
this.scene = markRaw(new THREE.Scene());
|
||||
this.scene = markRaw(new runtime.Scene());
|
||||
if (!this.noBackground) {
|
||||
this.scene.background = new THREE.Color(0xf0f0f0);
|
||||
this.scene.background = new runtime.Color(0xf0f0f0);
|
||||
await this.loadBackground();
|
||||
}
|
||||
|
||||
// Camera erstellen
|
||||
const aspect = container.clientWidth / container.clientHeight;
|
||||
this.camera = markRaw(new THREE.PerspectiveCamera(50, aspect, 0.1, 1000));
|
||||
this.camera = markRaw(new runtime.PerspectiveCamera(50, aspect, 0.1, 1000));
|
||||
this.camera.position.set(0, 1.5, 3);
|
||||
this.camera.lookAt(0, 1, 0);
|
||||
|
||||
// Renderer erstellen
|
||||
this.renderer = markRaw(new THREE.WebGLRenderer({ antialias: true, alpha: true }));
|
||||
this.renderer = markRaw(new runtime.WebGLRenderer({ antialias: true, alpha: true }));
|
||||
this.renderer.setSize(container.clientWidth, container.clientHeight);
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio);
|
||||
container.appendChild(this.renderer.domElement);
|
||||
|
||||
// Verbesserte Beleuchtung für hellere Modelle
|
||||
// Mehr ambient light für gleichmäßigere Ausleuchtung
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 1.0);
|
||||
const ambientLight = new runtime.AmbientLight(0xffffff, 1.0);
|
||||
this.scene.add(ambientLight);
|
||||
|
||||
// Hauptlicht von vorne oben - stärker
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
|
||||
const directionalLight = new runtime.DirectionalLight(0xffffff, 1.2);
|
||||
directionalLight.position.set(5, 10, 5);
|
||||
this.scene.add(directionalLight);
|
||||
|
||||
// Zusätzliches Licht von hinten - heller
|
||||
const backLight = new THREE.DirectionalLight(0xffffff, 0.75);
|
||||
const backLight = new runtime.DirectionalLight(0xffffff, 0.75);
|
||||
backLight.position.set(-5, 5, -5);
|
||||
this.scene.add(backLight);
|
||||
|
||||
// Zusätzliches Seitenlicht für mehr Tiefe
|
||||
const sideLight = new THREE.DirectionalLight(0xffffff, 0.5);
|
||||
const sideLight = new runtime.DirectionalLight(0xffffff, 0.5);
|
||||
sideLight.position.set(-5, 5, 5);
|
||||
this.scene.add(sideLight);
|
||||
|
||||
@@ -200,13 +228,13 @@ export default {
|
||||
},
|
||||
|
||||
async loadBackground() {
|
||||
const { THREE } = await this.ensureThreeRuntime();
|
||||
const runtime = await this.ensureThreeRuntime();
|
||||
// Optimierte Versionen (512×341, ~130 KB); Originale ~3 MB
|
||||
const backgrounds = ['bg1_opt.png', 'bg2_opt.png'];
|
||||
const randomBg = backgrounds[Math.floor(Math.random() * backgrounds.length)];
|
||||
const bgPath = `/images/falukant/backgrounds/${randomBg}`;
|
||||
|
||||
const loader = new THREE.TextureLoader();
|
||||
const loader = new runtime.TextureLoader();
|
||||
loader.load(
|
||||
bgPath,
|
||||
(texture) => {
|
||||
@@ -220,7 +248,7 @@ export default {
|
||||
console.warn('Fehler beim Laden des Hintergrunds:', error);
|
||||
// Fallback auf Standardfarbe bei Fehler
|
||||
if (this.scene) {
|
||||
this.scene.background = new THREE.Color(0xf0f0f0);
|
||||
this.scene.background = new runtime.Color(0xf0f0f0);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -228,7 +256,8 @@ export default {
|
||||
|
||||
async loadModel() {
|
||||
if (!this.scene) return;
|
||||
const { THREE, GLTFLoader, DRACOLoader } = await this.ensureThreeRuntime();
|
||||
const modelRuntime = await this.ensureThreeModelRuntime();
|
||||
const loaders = await this.ensureThreeLoaders();
|
||||
|
||||
// Altes Modell entfernen
|
||||
if (this.model) {
|
||||
@@ -252,9 +281,9 @@ export default {
|
||||
}
|
||||
|
||||
try {
|
||||
const dracoLoader = new DRACOLoader();
|
||||
const dracoLoader = new loaders.DRACOLoader();
|
||||
dracoLoader.setDecoderPath('/draco/gltf/');
|
||||
const loader = new GLTFLoader();
|
||||
const loader = new loaders.GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
const base = getApiBaseURL();
|
||||
@@ -273,12 +302,12 @@ export default {
|
||||
// Versuche zuerst genaues Alter
|
||||
try {
|
||||
gltf = await loader.loadAsync(exactAgePath);
|
||||
console.log(`Loaded exact age model: ${exactAgePath}`);
|
||||
console.debug(`Loaded exact age model: ${exactAgePath}`);
|
||||
} catch (exactAgeError) {
|
||||
// Falls genaues Alter nicht existiert, versuche Altersbereich
|
||||
try {
|
||||
gltf = await loader.loadAsync(ageGroupPath);
|
||||
console.log(`Loaded age group model: ${ageGroupPath}`);
|
||||
console.debug(`Loaded age group model: ${ageGroupPath}`);
|
||||
} catch (ageGroupError) {
|
||||
// Falls Altersbereich nicht existiert, verwende Basis-Modell
|
||||
console.warn(`Could not load ${ageGroupPath}, trying fallback model`);
|
||||
@@ -293,8 +322,8 @@ export default {
|
||||
this.model = markRaw(gltf.scene);
|
||||
|
||||
// Initiale Bounding Box für Größenberechnung (vor Skalierung)
|
||||
const initialBox = new THREE.Box3().setFromObject(this.model);
|
||||
const initialSize = initialBox.getSize(new THREE.Vector3());
|
||||
const initialBox = new modelRuntime.Box3().setFromObject(this.model);
|
||||
const initialSize = initialBox.getSize(new modelRuntime.Vector3());
|
||||
|
||||
// Skalierung basierend auf Alter
|
||||
const age = this.actualAge;
|
||||
@@ -318,8 +347,8 @@ export default {
|
||||
this.model.scale.set(modelScale, modelScale, modelScale);
|
||||
|
||||
// Bounding Box NACH dem Skalieren neu berechnen
|
||||
const scaledBox = new THREE.Box3().setFromObject(this.model);
|
||||
const scaledCenter = scaledBox.getCenter(new THREE.Vector3());
|
||||
const scaledBox = new modelRuntime.Box3().setFromObject(this.model);
|
||||
const scaledCenter = scaledBox.getCenter(new modelRuntime.Vector3());
|
||||
|
||||
// Modell zentrieren basierend auf der skalierten Bounding Box
|
||||
// Position direkt setzen statt zu subtrahieren, um Proxy-Probleme zu vermeiden
|
||||
@@ -331,7 +360,7 @@ export default {
|
||||
|
||||
// Animationen laden falls vorhanden
|
||||
if (gltf.animations && gltf.animations.length > 0) {
|
||||
this.mixer = markRaw(new THREE.AnimationMixer(this.model));
|
||||
this.mixer = markRaw(new modelRuntime.AnimationMixer(this.model));
|
||||
gltf.animations.forEach((clip) => {
|
||||
this.mixer.clipAction(clip).play();
|
||||
});
|
||||
|
||||
@@ -173,7 +173,7 @@ export default {
|
||||
this.fetchSettings();
|
||||
} catch (err) {
|
||||
console.error('Error updating setting:', err);
|
||||
showApiError(this, err, 'Aenderung konnte nicht gespeichert werden.');
|
||||
showApiError(this, err, 'Änderung konnte nicht gespeichert werden.');
|
||||
}
|
||||
},
|
||||
languagesList() {
|
||||
|
||||
@@ -279,7 +279,6 @@ export default {
|
||||
},
|
||||
|
||||
openNewDirectorDialog() {
|
||||
console.log('openNewDirectorDialog');
|
||||
this.$refs.newDirectorDialog.open(this.branchId);
|
||||
},
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
updateValue(value) {
|
||||
console.log('changed to ', value)
|
||||
this.$emit("input", parseInt(value));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user