forked from Simnation/Main
ed
This commit is contained in:
parent
028317e2ec
commit
7f51e16f6b
2 changed files with 527 additions and 67 deletions
|
@ -1,4 +1,6 @@
|
|||
let currentLicense = null;
|
||||
let isCardFlipped = false;
|
||||
let cameraStream = null;
|
||||
|
||||
// Event Listener für Nachrichten von FiveM
|
||||
window.addEventListener('message', function(event) {
|
||||
|
@ -8,6 +10,12 @@ window.addEventListener('message', function(event) {
|
|||
case 'showLicense':
|
||||
showLicense(data.data);
|
||||
break;
|
||||
case 'hideLicense':
|
||||
closeLicense();
|
||||
break;
|
||||
case 'openCamera':
|
||||
openCamera();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -17,75 +25,301 @@ function showLicense(data) {
|
|||
const container = document.getElementById('license-container');
|
||||
const card = document.getElementById('license-card');
|
||||
|
||||
// Lizenztyp-spezifische Klasse hinzufügen
|
||||
card.className = 'license-card ' + data.license.license_type;
|
||||
// Loading anzeigen
|
||||
showLoading();
|
||||
|
||||
// Header befüllen
|
||||
document.querySelector('.license-title').textContent = data.config.label;
|
||||
document.querySelector('.license-icon').className = 'license-icon ' + data.config.icon;
|
||||
|
||||
// Lizenzinformationen befüllen
|
||||
document.getElementById('license-name').textContent = data.license.name || 'N/A';
|
||||
document.getElementById('license-birthday').textContent = data.license.birthday || 'N/A';
|
||||
document.getElementById('license-gender').textContent = formatGender(data.license.gender) || 'N/A';
|
||||
document.getElementById('license-issue').textContent = data.license.issue_date || 'N/A';
|
||||
document.getElementById('license-expire').textContent = data.license.expire_date || 'N/A';
|
||||
|
||||
// Klassen anzeigen (nur bei Führerschein)
|
||||
const classesRow = document.getElementById('license-classes-row');
|
||||
if (data.license.classes && data.license.classes !== '[]') {
|
||||
try {
|
||||
const classes = JSON.parse(data.license.classes);
|
||||
if (classes && classes.length > 0) {
|
||||
document.getElementById('license-classes').textContent = classes.join(', ');
|
||||
classesRow.style.display = 'flex';
|
||||
} else {
|
||||
classesRow.style.display = 'none';
|
||||
}
|
||||
} catch (e) {
|
||||
classesRow.style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
classesRow.style.display = 'none';
|
||||
}
|
||||
|
||||
// Status anzeigen
|
||||
const statusElement = document.getElementById('license-status');
|
||||
if (data.license.is_active) {
|
||||
statusElement.textContent = '✅ Gültig';
|
||||
statusElement.className = 'license-status active';
|
||||
} else {
|
||||
statusElement.textContent = '❌ Ungültig';
|
||||
statusElement.className = 'license-status inactive';
|
||||
}
|
||||
|
||||
// Container anzeigen
|
||||
container.classList.remove('hidden');
|
||||
setTimeout(() => {
|
||||
// Lizenztyp-spezifische Klasse hinzufügen
|
||||
card.className = 'license-card ' + data.license.license_type;
|
||||
|
||||
// Header befüllen
|
||||
document.getElementById('license-title').textContent = data.config.label;
|
||||
document.getElementById('license-icon').className = 'license-icon ' + data.config.icon;
|
||||
|
||||
// Persönliche Daten
|
||||
document.getElementById('license-name').textContent = data.license.name || 'N/A';
|
||||
document.getElementById('license-birthday').textContent = formatDate(data.license.birthday) || 'N/A';
|
||||
document.getElementById('license-gender').textContent = formatGender(data.license.gender) || 'N/A';
|
||||
|
||||
// Dokument-Informationen
|
||||
document.getElementById('license-issue').textContent = formatDate(data.license.issue_date) || 'N/A';
|
||||
document.getElementById('license-expire').textContent = formatDate(data.license.expire_date) || 'N/A';
|
||||
document.getElementById('license-id').textContent = '#' + (data.license.id || '000000').toString().padStart(6, '0');
|
||||
document.getElementById('license-issuer').textContent = data.license.issued_by_name || 'Behörde';
|
||||
|
||||
// Foto anzeigen
|
||||
displayPlayerPhoto(data.license);
|
||||
|
||||
// Klassen anzeigen (nur bei Führerschein)
|
||||
displayLicenseClasses(data.license);
|
||||
|
||||
// Status und Gültigkeit
|
||||
displayLicenseStatus(data.license);
|
||||
displayValidityIndicator(data.license);
|
||||
|
||||
// Rückseite vorbereiten
|
||||
prepareBackSide(data.license);
|
||||
|
||||
// Container anzeigen
|
||||
hideLoading();
|
||||
container.classList.remove('hidden');
|
||||
|
||||
// Sound-Effekt
|
||||
playSound('card-flip-sound');
|
||||
|
||||
// Notification
|
||||
showNotification('Lizenz geladen', 'success');
|
||||
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// Foto anzeigen
|
||||
// Spieler-Foto anzeigen
|
||||
function displayPlayerPhoto(license) {
|
||||
const photoImg = document.getElementById('player-photo');
|
||||
const photoPlaceholder = document.getElementById('photo-placeholder');
|
||||
|
||||
if (data.license.photo_url && data.license.photo_url !== '') {
|
||||
// Echtes Foto anzeigen
|
||||
photoImg.src = data.license.photo_url;
|
||||
photoImg.classList.remove('hidden');
|
||||
photoPlaceholder.classList.add('hidden');
|
||||
if (license.photo_url && license.photo_url !== '') {
|
||||
photoImg.src = license.photo_url;
|
||||
photoImg.onload = function() {
|
||||
photoImg.classList.remove('hidden');
|
||||
photoPlaceholder.classList.add('hidden');
|
||||
};
|
||||
photoImg.onerror = function() {
|
||||
photoImg.classList.add('hidden');
|
||||
photoPlaceholder.classList.remove('hidden');
|
||||
};
|
||||
} else {
|
||||
// Platzhalter anzeigen
|
||||
photoImg.classList.add('hidden');
|
||||
photoPlaceholder.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// Geschlecht formatieren
|
||||
function formatGender(gender) {
|
||||
const genderMap = {
|
||||
'male': 'Männlich',
|
||||
'female': 'Weiblich',
|
||||
'other': 'Divers'
|
||||
};
|
||||
return genderMap[gender] || gender;
|
||||
// Lizenz-Klassen anzeigen
|
||||
function displayLicenseClasses(license) {
|
||||
const classesRow = document.getElementById('license-classes-row');
|
||||
const classesElement = document.getElementById('license-classes');
|
||||
|
||||
if (license.license_type === 'drivers_license' && license.classes && license.classes !== '[]') {
|
||||
try {
|
||||
const classes = JSON.parse(license.classes);
|
||||
if (classes && classes.length > 0) {
|
||||
classesElement.textContent = classes.join(', ');
|
||||
classesRow.style.display = 'flex';
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Fehler beim Parsen der Klassen:', e);
|
||||
}
|
||||
}
|
||||
classesRow.style.display = 'none';
|
||||
}
|
||||
|
||||
// Lizenz-Status anzeigen
|
||||
function displayLicenseStatus(license) {
|
||||
const statusElement = document.getElementById('license-status');
|
||||
const statusIcon = statusElement.querySelector('.status-icon');
|
||||
const statusText = statusElement.querySelector('.status-text');
|
||||
|
||||
// Ablaufdatum prüfen
|
||||
let isExpired = false;
|
||||
let isExpiringSoon = false;
|
||||
|
||||
if (license.expire_date) {
|
||||
const expireDate = new Date(license.expire_date);
|
||||
const today = new Date();
|
||||
const daysUntilExpire = Math.ceil((expireDate - today) / (1000 * 60 * 60 * 24));
|
||||
|
||||
isExpired = daysUntilExpire < 0;
|
||||
isExpiringSoon = daysUntilExpire <= 30 && daysUntilExpire >= 0;
|
||||
}
|
||||
|
||||
// Status setzen
|
||||
if (!license.is_active || isExpired) {
|
||||
statusElement.className = 'license-status inactive';
|
||||
statusIcon.className = 'status-icon fas fa-times-circle';
|
||||
statusText.textContent = isExpired ? 'Abgelaufen' : 'Ungültig';
|
||||
} else if (isExpiringSoon) {
|
||||
statusElement.className = 'license-status warning';
|
||||
statusIcon.className = 'status-icon fas fa-exclamation-triangle';
|
||||
statusText.textContent = 'Läuft bald ab';
|
||||
} else {
|
||||
statusElement.className = 'license-status active';
|
||||
statusIcon.className = 'status-icon fas fa-check-circle';
|
||||
statusText.textContent = 'Gültig';
|
||||
}
|
||||
}
|
||||
|
||||
// Gültigkeits-Indikator anzeigen
|
||||
function displayValidityIndicator(license) {
|
||||
const validityFill = document.getElementById('validity-fill');
|
||||
const validityText = document.getElementById('validity-text');
|
||||
|
||||
if (!license.expire_date) {
|
||||
validityText.textContent = 'Unbegrenzt gültig';
|
||||
validityFill.style.width = '100%';
|
||||
validityFill.style.backgroundColor = '#4CAF50';
|
||||
return;
|
||||
}
|
||||
|
||||
const issueDate = new Date(license.issue_date);
|
||||
const expireDate = new Date(license.expire_date);
|
||||
const today = new Date();
|
||||
|
||||
const totalDays = Math.ceil((expireDate - issueDate) / (1000 * 60 * 60 * 24));
|
||||
const remainingDays = Math.ceil((expireDate - today) / (1000 * 60 * 60 * 24));
|
||||
const percentage = Math.max(0, Math.min(100, (remainingDays / totalDays) * 100));
|
||||
|
||||
validityFill.style.width = percentage + '%';
|
||||
|
||||
if (remainingDays < 0) {
|
||||
validityText.textContent = 'Abgelaufen';
|
||||
validityFill.style.backgroundColor = '#f44336';
|
||||
} else if (remainingDays <= 30) {
|
||||
validityText.textContent = `Noch ${remainingDays} Tage gültig`;
|
||||
validityFill.style.backgroundColor = '#ff9800';
|
||||
} else {
|
||||
validityText.textContent = `Noch ${remainingDays} Tage gültig`;
|
||||
validityFill.style.backgroundColor = '#4CAF50';
|
||||
}
|
||||
}
|
||||
|
||||
// Rückseite vorbereiten
|
||||
function prepareBackSide(license) {
|
||||
const classesGrid = document.getElementById('classes-grid');
|
||||
const restrictionsList = document.getElementById('restrictions-list');
|
||||
const notesText = document.getElementById('notes-text');
|
||||
|
||||
// Klassen-Grid für Führerschein
|
||||
if (license.license_type === 'drivers_license' && license.classes) {
|
||||
try {
|
||||
const classes = JSON.parse(license.classes);
|
||||
classesGrid.innerHTML = '';
|
||||
|
||||
const classDescriptions = {
|
||||
'A': 'Motorräder',
|
||||
'A1': 'Leichte Motorräder',
|
||||
'A2': 'Mittlere Motorräder',
|
||||
'B': 'PKW',
|
||||
'BE': 'PKW mit Anhänger',
|
||||
'C': 'LKW',
|
||||
'CE': 'LKW mit Anhänger',
|
||||
'D': 'Bus',
|
||||
'DE': 'Bus mit Anhänger'
|
||||
};
|
||||
|
||||
classes.forEach(cls => {
|
||||
const classItem = document.createElement('div');
|
||||
classItem.className = 'class-item';
|
||||
classItem.innerHTML = `
|
||||
<div class="class-letter">${cls}</div>
|
||||
<div class="class-description">${classDescriptions[cls] || 'Unbekannt'}</div>
|
||||
`;
|
||||
classesGrid.appendChild(classItem);
|
||||
});
|
||||
} catch (e) {
|
||||
classesGrid.innerHTML = '<p>Keine Klassen verfügbar</p>';
|
||||
}
|
||||
} else {
|
||||
classesGrid.innerHTML = '<p>Nicht zutreffend</p>';
|
||||
}
|
||||
|
||||
// Beschränkungen (Beispiel)
|
||||
restrictionsList.innerHTML = '<li>Keine besonderen Beschränkungen</li>';
|
||||
|
||||
// Bemerkungen
|
||||
notesText.textContent = license.notes || 'Keine besonderen Bemerkungen';
|
||||
}
|
||||
|
||||
// Karte drehen
|
||||
function flipCard() {
|
||||
const frontSide = document.querySelector('.license-content, .license-footer');
|
||||
const backSide = document.getElementById('license-back');
|
||||
|
||||
isCardFlipped = !isCardFlipped;
|
||||
|
||||
if (isCardFlipped) {
|
||||
// Zur Rückseite
|
||||
document.querySelector('.license-content').classList.add('hidden');
|
||||
document.querySelector('.license-footer').classList.add('hidden');
|
||||
backSide.classList.remove('hidden');
|
||||
} else {
|
||||
// Zur Vorderseite
|
||||
document.querySelector('.license-content').classList.remove('hidden');
|
||||
document.querySelector('.license-footer').classList.remove('hidden');
|
||||
backSide.classList.add('hidden');
|
||||
}
|
||||
|
||||
playSound('card-flip-sound');
|
||||
}
|
||||
|
||||
// Kamera öffnen
|
||||
async function openCamera() {
|
||||
const container = document.getElementById('camera-container');
|
||||
const video = document.getElementById('camera-video');
|
||||
|
||||
try {
|
||||
cameraStream = await navigator.mediaDevices.getUserMedia({
|
||||
video: {
|
||||
width: 640,
|
||||
height: 480,
|
||||
facingMode: 'user'
|
||||
}
|
||||
});
|
||||
|
||||
video.srcObject = cameraStream;
|
||||
container.classList.remove('hidden');
|
||||
|
||||
showNotification('Kamera geöffnet', 'info');
|
||||
} catch (err) {
|
||||
console.error('Kamera-Zugriff fehlgeschlagen:', err);
|
||||
showNotification('Kamera-Zugriff fehlgeschlagen', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Foto aufnehmen
|
||||
function takePhoto() {
|
||||
const video = document.getElementById('camera-video');
|
||||
const canvas = document.getElementById('camera-canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
ctx.drawImage(video, 0, 0);
|
||||
|
||||
const photoData = canvas.toDataURL('image/jpeg', 0.8);
|
||||
|
||||
// Sound-Effekt
|
||||
playSound('camera-shutter-sound');
|
||||
|
||||
// An FiveM senden
|
||||
fetch(`https://${GetParentResourceName()}/savePhoto`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
photo: photoData,
|
||||
citizenid: currentLicense?.license?.citizenid
|
||||
})
|
||||
}).then(() => {
|
||||
showNotification('Foto gespeichert', 'success');
|
||||
closeCamera();
|
||||
}).catch(err => {
|
||||
console.error('Fehler beim Speichern:', err);
|
||||
showNotification('Fehler beim Speichern', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// Kamera schließen
|
||||
function closeCamera() {
|
||||
const container = document.getElementById('camera-container');
|
||||
|
||||
if (cameraStream) {
|
||||
cameraStream.getTracks().forEach(track => track.stop());
|
||||
cameraStream = null;
|
||||
}
|
||||
|
||||
container.classList.add('hidden');
|
||||
}
|
||||
|
||||
// Lizenz schließen
|
||||
|
@ -93,26 +327,121 @@ function closeLicense() {
|
|||
const container = document.getElementById('license-container');
|
||||
container.classList.add('hidden');
|
||||
|
||||
// Callback an FiveM senden
|
||||
// Karte zurücksetzen
|
||||
isCardFlipped = false;
|
||||
document.querySelector('.license-content').classList.remove('hidden');
|
||||
document.querySelector('.license-footer').classList.remove('hidden');
|
||||
document.getElementById('license-back').classList.add('hidden');
|
||||
|
||||
// Callback an FiveM
|
||||
fetch(`https://${GetParentResourceName()}/closeLicense`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({})
|
||||
});
|
||||
}).catch(() => {}); // Fehler ignorieren
|
||||
}
|
||||
|
||||
// ESC-Taste zum Schließen
|
||||
// Hilfsfunktionen
|
||||
function formatGender(gender) {
|
||||
const genderMap = {
|
||||
'male': 'Männlich',
|
||||
'female': 'Weiblich',
|
||||
'other': 'Divers',
|
||||
'm': 'Männlich',
|
||||
'f': 'Weiblich'
|
||||
};
|
||||
return genderMap[gender?.toLowerCase()] || gender || 'Unbekannt';
|
||||
}
|
||||
|
||||
function formatDate(dateString) {
|
||||
if (!dateString) return null;
|
||||
|
||||
try {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('de-DE');
|
||||
} catch (e) {
|
||||
return dateString;
|
||||
}
|
||||
}
|
||||
|
||||
function showLoading() {
|
||||
document.getElementById('loading-overlay').classList.remove('hidden');
|
||||
}
|
||||
|
||||
function hideLoading() {
|
||||
document.getElementById('loading-overlay').classList.add('hidden');
|
||||
}
|
||||
|
||||
function playSound(soundId) {
|
||||
const audio = document.getElementById(soundId);
|
||||
if (audio) {
|
||||
audio.volume = 0.3;
|
||||
audio.play().catch(() => {}); // Fehler ignorieren
|
||||
}
|
||||
}
|
||||
|
||||
function showNotification(message, type = 'info') {
|
||||
const container = document.getElementById('notification-container');
|
||||
const notification = document.createElement('div');
|
||||
|
||||
notification.className = `notification ${type}`;
|
||||
notification.innerHTML = `
|
||||
<div class="notification-content">
|
||||
<i class="notification-icon fas ${getNotificationIcon(type)}"></i>
|
||||
<span class="notification-text">${message}</span>
|
||||
</div>
|
||||
<button class="notification-close" onclick="this.parentElement.remove()">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
`;
|
||||
|
||||
container.appendChild(notification);
|
||||
|
||||
// Auto-remove nach 5 Sekunden
|
||||
setTimeout(() => {
|
||||
if (notification.parentElement) {
|
||||
notification.remove();
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function getNotificationIcon(type) {
|
||||
const icons = {
|
||||
'success': 'fa-check-circle',
|
||||
'error': 'fa-exclamation-circle',
|
||||
'warning': 'fa-exclamation-triangle',
|
||||
'info': 'fa-info-circle'
|
||||
};
|
||||
return icons[type] || icons.info;
|
||||
}
|
||||
|
||||
// Event Listeners
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape') {
|
||||
if (!document.getElementById('camera-container').classList.contains('hidden')) {
|
||||
closeCamera();
|
||||
} else if (!document.getElementById('license-container').classList.contains('hidden')) {
|
||||
closeLicense();
|
||||
}
|
||||
}
|
||||
|
||||
if (event.key === 'f' || event.key === 'F') {
|
||||
if (!document.getElementById('license-container').classList.contains('hidden')) {
|
||||
flipCard();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Klick außerhalb zum Schließen
|
||||
document.getElementById('license-container').addEventListener('click', function(event) {
|
||||
if (event.target.classList.contains('license-overlay')) {
|
||||
closeLicense();
|
||||
}
|
||||
});
|
||||
|
||||
// Klick außerhalb der Karte zum Schließen
|
||||
document.getElementById('license-container').addEventListener('click', function(event) {
|
||||
if (event.target === this) {
|
||||
closeLicense();
|
||||
}
|
||||
// Initialisierung
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('License System UI geladen');
|
||||
});
|
||||
|
|
|
@ -235,3 +235,134 @@ body {
|
|||
.license-card {
|
||||
animation: slideIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* Notification System */
|
||||
#notification-container {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 10000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.notification {
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
color: white;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-width: 300px;
|
||||
animation: slideInRight 0.3s ease;
|
||||
}
|
||||
|
||||
.notification.success { border-left: 4px solid #4CAF50; }
|
||||
.notification.error { border-left: 4px solid #f44336; }
|
||||
.notification.warning { border-left: 4px solid #ff9800; }
|
||||
.notification.info { border-left: 4px solid #2196F3; }
|
||||
|
||||
.notification-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.notification-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
/* Loading Overlay */
|
||||
#loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||
border-top: 3px solid white;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto 20px;
|
||||
}
|
||||
|
||||
/* Kamera Interface */
|
||||
#camera-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9998;
|
||||
}
|
||||
|
||||
.camera-interface {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
max-width: 600px;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.camera-preview {
|
||||
position: relative;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
#camera-video {
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.face-guide {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.guide-circle {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.8);
|
||||
border-radius: 50%;
|
||||
margin: 0 auto 10px;
|
||||
}
|
||||
|
||||
/* Animationen */
|
||||
@keyframes slideInRight {
|
||||
from { transform: translateX(100%); opacity: 0; }
|
||||
to { transform: translateX(0); opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue