Update changes
Dieser Commit ist enthalten in:
@ -4,7 +4,9 @@
|
||||
"Bash(mkdir:*)",
|
||||
"Bash(npm install)",
|
||||
"Bash(npm run build-win:*)",
|
||||
"Bash(chmod:*)"
|
||||
"Bash(chmod:*)",
|
||||
"Bash(ls:*)",
|
||||
"Bash(cp:*)"
|
||||
],
|
||||
"deny": []
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
- **Path**: `C:/Users/hendr/Desktop/IntelSight/Projektablage/Toolbox-Metadaten-Crawler`
|
||||
- **Files**: 88 files
|
||||
- **Size**: 275.2 MB
|
||||
- **Last Modified**: 2025-07-10 19:19
|
||||
- **Last Modified**: 2025-07-10 19:36
|
||||
|
||||
## Technology Stack
|
||||
|
||||
@ -87,3 +87,4 @@ This project is managed with Claude Project Manager. To work with this project:
|
||||
- README updated on 2025-07-08 20:45:50
|
||||
- README updated on 2025-07-10 16:11:59
|
||||
- README updated on 2025-07-10 19:34:36
|
||||
- README updated on 2025-07-10 23:16:36
|
||||
|
||||
97
app.js
97
app.js
@ -311,9 +311,14 @@ function createMetadataSection(title, data, icon = '📋', cssClass = '') {
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
const formattedKey = formatMetadataKey(key);
|
||||
const formattedValue = formatMetadataValue(key, value);
|
||||
const tooltip = getMetadataTooltip(key, formattedKey);
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td>${formattedKey}</td>
|
||||
<td>
|
||||
${formattedKey}
|
||||
${tooltip ? `<span class="info-icon" title="${tooltip}"><img src="icons/info.svg" alt="Info"></span>` : ''}
|
||||
</td>
|
||||
<td>${formattedValue}</td>
|
||||
</tr>
|
||||
`;
|
||||
@ -518,29 +523,48 @@ function formatMetadataKey(key) {
|
||||
// Remove common prefixes and format
|
||||
key = key.replace(/^(EXIF|GPS|IPTC|XMP)/, '');
|
||||
|
||||
// Add spaces before capital letters
|
||||
key = key.replace(/([A-Z])/g, ' $1').trim();
|
||||
|
||||
// Special formatting for known keys
|
||||
// Special formatting for known keys - do first before adding spaces
|
||||
const keyMap = {
|
||||
'Make': 'Kamera-Hersteller',
|
||||
'Model': 'Kamera-Modell',
|
||||
'DateTime Original': 'Aufnahmedatum',
|
||||
'DateTimeOriginal': 'Aufnahmedatum',
|
||||
'Exposure Time': 'Belichtungszeit',
|
||||
'ExposureTime': 'Belichtungszeit',
|
||||
'F Number': 'Blende',
|
||||
'FNumber': 'Blende',
|
||||
'ISO Speed Ratings': 'ISO-Wert',
|
||||
'ISOSpeedRatings': 'ISO-Wert',
|
||||
'Focal Length': 'Brennweite',
|
||||
'FocalLength': 'Brennweite',
|
||||
'Flash': 'Blitz',
|
||||
'GPS Latitude': 'Breitengrad',
|
||||
'GPSLatitude': 'Breitengrad',
|
||||
'GPS Longitude': 'Längengrad',
|
||||
'GPSLongitude': 'Längengrad',
|
||||
'GPS Altitude': 'Höhe',
|
||||
'GPSAltitude': 'Höhe',
|
||||
'Lens Model': 'Objektiv',
|
||||
'LensModel': 'Objektiv',
|
||||
'White Balance': 'Weißabgleich',
|
||||
'WhiteBalance': 'Weißabgleich',
|
||||
'Exposure Mode': 'Belichtungsmodus',
|
||||
'Color Space': 'Farbraum'
|
||||
'ExposureMode': 'Belichtungsmodus',
|
||||
'Color Space': 'Farbraum',
|
||||
'ColorSpace': 'Farbraum'
|
||||
};
|
||||
|
||||
return keyMap[key.trim()] || key;
|
||||
// Check if we have a known key first
|
||||
if (keyMap[key]) {
|
||||
return keyMap[key];
|
||||
}
|
||||
|
||||
// Add spaces before capital letters but preserve acronyms
|
||||
key = key.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2'); // For cases like "GPSLatitude" -> "GPS Latitude"
|
||||
key = key.replace(/([a-z\d])([A-Z])/g, '$1 $2'); // For cases like "dateTime" -> "date Time"
|
||||
key = key.trim();
|
||||
|
||||
return keyMap[key] || key;
|
||||
}
|
||||
|
||||
// Format metadata values for display
|
||||
@ -632,6 +656,65 @@ let currentFileData = null;
|
||||
let currentMetadata = null;
|
||||
let currentPreviewUrl = null;
|
||||
|
||||
// Get tooltips for metadata fields
|
||||
function getMetadataTooltip(key, formattedKey) {
|
||||
const tooltips = {
|
||||
'ISO-Wert': 'Die Lichtempfindlichkeit des Kamerasensors. Höhere Werte (z.B. 1600) bedeuten mehr Empfindlichkeit, aber auch mehr Bildrauschen.',
|
||||
'Blende': 'Die Öffnung des Objektivs (f-Zahl). Kleinere Zahlen (z.B. f/1.8) bedeuten eine größere Öffnung und mehr Licht.',
|
||||
'Belichtungszeit': 'Wie lange der Kamerasensor dem Licht ausgesetzt ist. Z.B. 1/100 bedeutet eine Hundertstelsekunde.',
|
||||
'Brennweite': 'Der Abstand zwischen Objektiv und Sensor in Millimetern. Bestimmt den Bildausschnitt.',
|
||||
'Weißabgleich': 'Einstellung zur korrekten Farbwiedergabe unter verschiedenen Lichtbedingungen.',
|
||||
'Belichtungsmodus': 'Automatik, Manuell, Blendenpriorität oder Zeitpriorität - bestimmt wie die Kamera die Belichtung steuert.',
|
||||
'Farbraum': 'Definiert den Bereich der darstellbaren Farben (z.B. sRGB für Web, Adobe RGB für Druck).',
|
||||
'Breitengrad': 'GPS-Koordinate für die Nord-Süd-Position des Aufnahmeortes.',
|
||||
'Längengrad': 'GPS-Koordinate für die Ost-West-Position des Aufnahmeortes.',
|
||||
'Höhe': 'Höhe über dem Meeresspiegel am Aufnahmeort.',
|
||||
'Objektiv': 'Das verwendete Kameraobjektiv mit seinen technischen Eigenschaften.',
|
||||
'Blitz': 'Informationen darüber, ob und wie der Blitz verwendet wurde.',
|
||||
'ExposureCompensation': 'Belichtungskorrektur - manuelle Anpassung der automatischen Belichtung.',
|
||||
'MeteringMode': 'Messmethode für die Belichtung (Spot, Matrix, Mittenbetont).',
|
||||
'FocalLengthIn35mmFilm': 'Brennweite umgerechnet auf Kleinbildformat für bessere Vergleichbarkeit.',
|
||||
'DigitalZoomRatio': 'Digitaler Zoom-Faktor - elektronische Vergrößerung mit Qualitätsverlust.',
|
||||
'SceneCaptureType': 'Art der Aufnahme (Landschaft, Portrait, Nachtaufnahme).',
|
||||
'SubjectDistanceRange': 'Entfernungsbereich zum Motiv (Makro, Nah, Fern).',
|
||||
'Sharpness': 'Nachschärfung - digitale Kantenbetonung des Bildes.',
|
||||
'Saturation': 'Farbsättigung - Intensität der Farben im Bild.',
|
||||
'Contrast': 'Kontrast - Unterschied zwischen hellen und dunklen Bereichen.',
|
||||
'GainControl': 'Verstärkungsregelung - elektronische Signalverstärkung bei wenig Licht.',
|
||||
// Neue Erklärungen
|
||||
'ApertureValue': 'Blendenwert in APEX-Einheiten - technische Darstellung der Blendenöffnung für Berechnungen.',
|
||||
'Aperture Value': 'Blendenwert in APEX-Einheiten - technische Darstellung der Blendenöffnung für Berechnungen.',
|
||||
'ExposureBiasValue': 'Belichtungskorrektur in EV-Stufen. +1 bedeutet doppelt so hell, -1 halb so hell.',
|
||||
'Exposure Bias Value': 'Belichtungskorrektur in EV-Stufen. +1 bedeutet doppelt so hell, -1 halb so hell.',
|
||||
'MaxApertureValue': 'Größte Blendenöffnung des Objektivs (kleinste f-Zahl) - bestimmt die maximale Lichtmenge.',
|
||||
'Max Aperture Value': 'Größte Blendenöffnung des Objektivs (kleinste f-Zahl) - bestimmt die maximale Lichtmenge.',
|
||||
'ExposureProgram': 'Kameraeinstellung: 0=Unbekannt, 1=Manuell, 2=Normal, 3=Blendenpriorität, 4=Zeitpriorität, 5=Kreativ, 6=Action, 7=Portrait, 8=Landschaft.',
|
||||
'Exposure Program': 'Kameraeinstellung: 0=Unbekannt, 1=Manuell, 2=Normal, 3=Blendenpriorität, 4=Zeitpriorität, 5=Kreativ, 6=Action, 7=Portrait, 8=Landschaft.',
|
||||
'SubSampling': 'Farbunterabtastung bei JPEG - bestimmt wie Farbinformationen gespeichert werden (4:2:2 oder 4:2:0).',
|
||||
'YCbCrSubSampling': 'Farbunterabtastung bei JPEG - bestimmt wie Farbinformationen gespeichert werden (4:2:2 oder 4:2:0).',
|
||||
'Orientation': 'Bildausrichtung: 1=Normal, 3=180° gedreht, 6=90° rechts gedreht, 8=90° links gedreht.',
|
||||
'YCbCrPositioning': 'Position der Farbinformationen: 1=Zentriert (üblich), 2=Co-sited (professionell).',
|
||||
'Y Cb Cr Positioning': 'Position der Farbinformationen: 1=Zentriert (üblich), 2=Co-sited (professionell).',
|
||||
'ExifIFDPointer': 'Technischer Verweis auf den Speicherort der EXIF-Daten in der Datei.',
|
||||
'EXIF IFD Pointer': 'Technischer Verweis auf den Speicherort der EXIF-Daten in der Datei.',
|
||||
'ExifVersion': 'Version des EXIF-Standards (z.B. 0232 = Version 2.32) - bestimmt verfügbare Metadatenfelder.',
|
||||
'EXIF Version': 'Version des EXIF-Standards (z.B. 0232 = Version 2.32) - bestimmt verfügbare Metadatenfelder.',
|
||||
'ShutterSpeedValue': 'Verschlusszeit in APEX-Einheiten - technische Darstellung für Berechnungen.',
|
||||
'Shutter Speed Value': 'Verschlusszeit in APEX-Einheiten - technische Darstellung für Berechnungen.',
|
||||
'BrightnessValue': 'Objekthelligkeit in APEX-Einheiten - Messwert der Motivhelligkeit.',
|
||||
'Brightness Value': 'Objekthelligkeit in APEX-Einheiten - Messwert der Motivhelligkeit.',
|
||||
'OffsetTime': 'Zeitzonenversatz zur UTC-Zeit bei der Aufnahme (z.B. +02:00 für MESZ).',
|
||||
'Offset Time': 'Zeitzonenversatz zur UTC-Zeit bei der Aufnahme (z.B. +02:00 für MESZ).',
|
||||
'OffsetTimeOriginal': 'Ursprünglicher Zeitzonenversatz bei der Aufnahme - bleibt bei Bearbeitung erhalten.',
|
||||
'Offset Time Original': 'Ursprünglicher Zeitzonenversatz bei der Aufnahme - bleibt bei Bearbeitung erhalten.',
|
||||
'ImageUniqueID': 'Einzigartige Bild-ID aus Datum, Kameraseriennummer und Bildnummer - identifiziert das Bild eindeutig.',
|
||||
'Image Unique ID': 'Einzigartige Bild-ID aus Datum, Kameraseriennummer und Bildnummer - identifiziert das Bild eindeutig.'
|
||||
};
|
||||
|
||||
// Check both the original key and formatted key
|
||||
return tooltips[formattedKey] || tooltips[key] || null;
|
||||
}
|
||||
|
||||
// Generate PDF report
|
||||
async function generateReport() {
|
||||
if (!currentFileData) {
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
Push Debug Info - 2025-07-10 19:11:49.841754
|
||||
Repository: Metadaten-Crawler
|
||||
Push Debug Info - 2025-07-10 19:36:09.172689
|
||||
Repository: Toolbox-Metadaten-Crawler
|
||||
Owner: IntelSight
|
||||
Path: C:\Users\hendr\Desktop\IntelSight\Projektablage\Metadaten-Crawler
|
||||
Path: C:\Users\hendr\Desktop\IntelSight\Projektablage\Toolbox-Metadaten-Crawler
|
||||
Current branch: master
|
||||
Git remotes:
|
||||
origin https://IntelSight_Admin:3b4a6ba1ade3f34640f3c85d2333b4a3a0627471@gitea-undso.intelsight.de/IntelSight/Metadaten-Crawler.git (fetch)
|
||||
origin https://IntelSight_Admin:3b4a6ba1ade3f34640f3c85d2333b4a3a0627471@gitea-undso.intelsight.de/IntelSight/Metadaten-Crawler.git (push)
|
||||
origin https://IntelSight_Admin:3b4a6ba1ade3f34640f3c85d2333b4a3a0627471@gitea-undso.intelsight.de/IntelSight/Toolbox-Metadaten-Crawler.git (fetch)
|
||||
origin https://IntelSight_Admin:3b4a6ba1ade3f34640f3c85d2333b4a3a0627471@gitea-undso.intelsight.de/IntelSight/Toolbox-Metadaten-Crawler.git (push)
|
||||
Git status before push:
|
||||
Clean
|
||||
Push command: git push --set-upstream origin master:main -v
|
||||
@ -13,10 +13,10 @@ Push result: Success
|
||||
Push stdout:
|
||||
branch 'master' set up to track 'origin/main'.
|
||||
Push stderr:
|
||||
POST git-receive-pack (52750 bytes)
|
||||
POST git-receive-pack (55591 bytes)
|
||||
remote: . Processing 1 references
|
||||
remote: Processed 1 references in total
|
||||
Pushing to https://gitea-undso.intelsight.de/IntelSight/Metadaten-Crawler.git
|
||||
To https://gitea-undso.intelsight.de/IntelSight/Metadaten-Crawler.git
|
||||
Pushing to https://gitea-undso.intelsight.de/IntelSight/Toolbox-Metadaten-Crawler.git
|
||||
To https://gitea-undso.intelsight.de/IntelSight/Toolbox-Metadaten-Crawler.git
|
||||
* [new branch] master -> main
|
||||
updating local tracking ref 'refs/remotes/origin/main'
|
||||
4
icons/info.svg
Normale Datei
4
icons/info.svg
Normale Datei
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 8H12.01M12 11V16M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Nachher Breite: | Höhe: | Größe: 454 B |
4
icons/moon.svg
Normale Datei
4
icons/moon.svg
Normale Datei
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.32031 11.6835C3.32031 16.6541 7.34975 20.6835 12.3203 20.6835C16.1075 20.6835 19.3483 18.3443 20.6768 15.032C19.6402 15.4486 18.5059 15.6834 17.3203 15.6834C12.3497 15.6834 8.32031 11.654 8.32031 6.68342C8.32031 5.50338 8.55165 4.36259 8.96453 3.32996C5.65605 4.66028 3.32031 7.89912 3.32031 11.6835Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Nachher Breite: | Höhe: | Größe: 624 B |
5
icons/settings.svg
Normale Datei
5
icons/settings.svg
Normale Datei
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15 12C15 13.6569 13.6569 15 12 15C10.3431 15 9 13.6569 9 12C9 10.3431 10.3431 9 12 9C13.6569 9 15 10.3431 15 12Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12.9046 3.06005C12.6988 3 12.4659 3 12 3C11.5341 3 11.3012 3 11.0954 3.06005C10.7942 3.14794 10.5281 3.32808 10.3346 3.57511C10.2024 3.74388 10.1159 3.96016 9.94291 4.39272C9.69419 5.01452 9.00393 5.33471 8.36857 5.123L7.79779 4.93281C7.3929 4.79785 7.19045 4.73036 6.99196 4.7188C6.70039 4.70181 6.4102 4.77032 6.15701 4.9159C5.98465 5.01501 5.83376 5.16591 5.53197 5.4677C5.21122 5.78845 5.05084 5.94882 4.94896 6.13189C4.79927 6.40084 4.73595 6.70934 4.76759 7.01551C4.78912 7.2239 4.87335 7.43449 5.04182 7.85566C5.30565 8.51523 5.05184 9.26878 4.44272 9.63433L4.16521 9.80087C3.74031 10.0558 3.52786 10.1833 3.37354 10.3588C3.23698 10.5141 3.13401 10.696 3.07109 10.893C3 11.1156 3 11.3658 3 11.8663C3 12.4589 3 12.7551 3.09462 13.0088C3.17823 13.2329 3.31422 13.4337 3.49124 13.5946C3.69158 13.7766 3.96395 13.8856 4.50866 14.1035C5.06534 14.3261 5.35196 14.9441 5.16236 15.5129L4.94721 16.1584C4.79819 16.6054 4.72367 16.829 4.7169 17.0486C4.70875 17.3127 4.77049 17.5742 4.89587 17.8067C5.00015 18.0002 5.16678 18.1668 5.5 18.5C5.83323 18.8332 5.99985 18.9998 6.19325 19.1041C6.4258 19.2295 6.68733 19.2913 6.9514 19.2831C7.17102 19.2763 7.39456 19.2018 7.84164 19.0528L8.36862 18.8771C9.00393 18.6654 9.6942 18.9855 9.94291 19.6073C10.1159 20.0398 10.2024 20.2561 10.3346 20.4249C10.5281 20.6719 10.7942 20.8521 11.0954 20.94C11.3012 21 11.5341 21 12 21C12.4659 21 12.6988 21 12.9046 20.94C13.2058 20.8521 13.4719 20.6719 13.6654 20.4249C13.7976 20.2561 13.8841 20.0398 14.0571 19.6073C14.3058 18.9855 14.9961 18.6654 15.6313 18.8773L16.1579 19.0529C16.605 19.2019 16.8286 19.2764 17.0482 19.2832C17.3123 19.2913 17.5738 19.2296 17.8063 19.1042C17.9997 18.9999 18.1664 18.8333 18.4996 18.5001C18.8328 18.1669 18.9994 18.0002 19.1037 17.8068C19.2291 17.5743 19.2908 17.3127 19.2827 17.0487C19.2759 16.8291 19.2014 16.6055 19.0524 16.1584L18.8374 15.5134C18.6477 14.9444 18.9344 14.3262 19.4913 14.1035C20.036 13.8856 20.3084 13.7766 20.5088 13.5946C20.6858 13.4337 20.8218 13.2329 20.9054 13.0088C21 12.7551 21 12.4589 21 11.8663C21 11.3658 21 11.1156 20.9289 10.893C20.866 10.696 20.763 10.5141 20.6265 10.3588C20.4721 10.1833 20.2597 10.0558 19.8348 9.80087L19.5569 9.63416C18.9478 9.26867 18.6939 8.51514 18.9578 7.85558C19.1262 7.43443 19.2105 7.22383 19.232 7.01543C19.2636 6.70926 19.2003 6.40077 19.0506 6.13181C18.9487 5.94875 18.7884 5.78837 18.4676 5.46762C18.1658 5.16584 18.0149 5.01494 17.8426 4.91583C17.5894 4.77024 17.2992 4.70174 17.0076 4.71872C16.8091 4.73029 16.6067 4.79777 16.2018 4.93273L15.6314 5.12287C14.9961 5.33464 14.3058 5.0145 14.0571 4.39272C13.8841 3.96016 13.7976 3.74388 13.6654 3.57511C13.4719 3.32808 13.2058 3.14794 12.9046 3.06005Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Nachher Breite: | Höhe: | Größe: 3.1 KiB |
4
icons/sun.svg
Normale Datei
4
icons/sun.svg
Normale Datei
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 3V4M12 20V21M4 12H3M6.31412 6.31412L5.5 5.5M17.6859 6.31412L18.5 5.5M6.31412 17.69L5.5 18.5001M17.6859 17.69L18.5 18.5001M21 12H20M16 12C16 14.2091 14.2091 16 12 16C9.79086 16 8 14.2091 8 12C8 9.79086 9.79086 8 12 8C14.2091 8 16 9.79086 16 12Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Nachher Breite: | Höhe: | Größe: 568 B |
38
index.html
38
index.html
@ -20,45 +20,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings Dialog -->
|
||||
<div class="settings-dialog" id="settingsDialog">
|
||||
<div class="settings-content">
|
||||
<div class="settings-header">
|
||||
<h2>Einstellungen</h2>
|
||||
<button class="settings-close" id="settingsCloseBtn">×</button>
|
||||
</div>
|
||||
<div class="settings-body">
|
||||
<div class="settings-section">
|
||||
<h3>Erscheinungsbild</h3>
|
||||
<div class="theme-selector">
|
||||
<label class="theme-option">
|
||||
<input type="radio" name="theme" value="dark" id="darkTheme" checked>
|
||||
<span class="theme-label">
|
||||
<span class="theme-icon">🌙</span>
|
||||
<span>Dark Mode</span>
|
||||
</span>
|
||||
</label>
|
||||
<label class="theme-option">
|
||||
<input type="radio" name="theme" value="light" id="lightTheme">
|
||||
<span class="theme-label">
|
||||
<span class="theme-icon">☀️</span>
|
||||
<span>Light Mode</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="app-header">
|
||||
<div class="app-header-content">
|
||||
<h1>Metadaten-Crawler</h1>
|
||||
<button class="settings-btn" id="settingsBtn" title="Einstellungen">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
<path d="M12 1v6m0 6v6m9-9h-6m-6 0H3m16.83-4.24l-4.24 4.24m-7.18 0L4.17 4.76m16.66 14.48l-4.24-4.24m-7.18 0L4.17 19.24"></path>
|
||||
</svg>
|
||||
<button class="theme-toggle-btn" id="themeToggleBtn" title="Theme umschalten">
|
||||
<img src="icons/moon.svg" class="theme-icon dark-icon" alt="Dark Mode">
|
||||
<img src="icons/sun.svg" class="theme-icon light-icon" alt="Light Mode">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
53
renderer.js
53
renderer.js
@ -14,10 +14,12 @@ function applyTheme(darkMode) {
|
||||
isDarkMode = darkMode;
|
||||
if (darkMode) {
|
||||
document.body.classList.remove('light-mode');
|
||||
document.getElementById('darkTheme').checked = true;
|
||||
} else {
|
||||
document.body.classList.add('light-mode');
|
||||
document.getElementById('lightTheme').checked = true;
|
||||
}
|
||||
// Save theme preference
|
||||
if (window.electronAPI) {
|
||||
window.electronAPI.setTheme(darkMode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,32 +36,11 @@ document.getElementById('closeBtn').addEventListener('click', () => {
|
||||
if (window.electronAPI) window.electronAPI.closeWindow();
|
||||
});
|
||||
|
||||
// Settings dialog
|
||||
const settingsDialog = document.getElementById('settingsDialog');
|
||||
const settingsBtn = document.getElementById('settingsBtn');
|
||||
const settingsCloseBtn = document.getElementById('settingsCloseBtn');
|
||||
// Theme toggle button
|
||||
const themeToggleBtn = document.getElementById('themeToggleBtn');
|
||||
|
||||
settingsBtn.addEventListener('click', () => {
|
||||
settingsDialog.classList.add('show');
|
||||
});
|
||||
|
||||
settingsCloseBtn.addEventListener('click', () => {
|
||||
settingsDialog.classList.remove('show');
|
||||
});
|
||||
|
||||
settingsDialog.addEventListener('click', (e) => {
|
||||
if (e.target === settingsDialog) {
|
||||
settingsDialog.classList.remove('show');
|
||||
}
|
||||
});
|
||||
|
||||
// Theme radio buttons
|
||||
document.getElementById('darkTheme').addEventListener('change', () => {
|
||||
applyTheme(true);
|
||||
});
|
||||
|
||||
document.getElementById('lightTheme').addEventListener('change', () => {
|
||||
applyTheme(false);
|
||||
themeToggleBtn.addEventListener('click', () => {
|
||||
applyTheme(!isDarkMode);
|
||||
});
|
||||
|
||||
// Listen for theme changes from menu
|
||||
@ -76,4 +57,20 @@ if (window.electronAPI) {
|
||||
// Initialize on load
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
initializeTheme();
|
||||
});
|
||||
});
|
||||
|
||||
// Store theme preference
|
||||
function setTheme(darkMode) {
|
||||
localStorage.setItem('theme', darkMode ? 'dark' : 'light');
|
||||
}
|
||||
|
||||
// Get theme preference
|
||||
function getStoredTheme() {
|
||||
const storedTheme = localStorage.getItem('theme');
|
||||
return storedTheme !== 'light';
|
||||
}
|
||||
|
||||
// Initialize theme from stored preference
|
||||
if (!window.electronAPI) {
|
||||
applyTheme(getStoredTheme());
|
||||
}
|
||||
265
styles.css
265
styles.css
@ -274,6 +274,7 @@ body.light-mode .metadata-content {
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body.light-mode .metadata-table td:first-child {
|
||||
@ -334,9 +335,12 @@ body.light-mode .metadata-table td:first-child {
|
||||
font-size: 16px;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
font-weight: 600;
|
||||
margin-top: 24px;
|
||||
transition: all 0.3s ease;
|
||||
letter-spacing: 0.5px;
|
||||
height: 48px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.clear-btn:hover {
|
||||
@ -417,7 +421,7 @@ body.light-mode .title-bar {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.settings-btn {
|
||||
.theme-toggle-btn {
|
||||
background-color: var(--secondary-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
color: var(--accent);
|
||||
@ -428,15 +432,43 @@ body.light-mode .title-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.settings-btn:hover {
|
||||
.theme-toggle-btn:hover {
|
||||
background-color: var(--secondary-bg-hover);
|
||||
border-color: var(--accent);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 212, 255, 0.2);
|
||||
}
|
||||
|
||||
.theme-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
position: absolute;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.theme-icon.dark-icon {
|
||||
opacity: 1;
|
||||
filter: brightness(0) saturate(100%) invert(88%) sepia(61%) saturate(3812%) hue-rotate(154deg) brightness(101%) contrast(101%);
|
||||
}
|
||||
|
||||
.theme-icon.light-icon {
|
||||
opacity: 0;
|
||||
filter: brightness(0) saturate(100%) invert(74%) sepia(91%) saturate(5214%) hue-rotate(355deg) brightness(103%) contrast(104%);
|
||||
}
|
||||
|
||||
body.light-mode .theme-icon.dark-icon {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
body.light-mode .theme-icon.light-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.window-control {
|
||||
background: transparent;
|
||||
border: none;
|
||||
@ -459,139 +491,108 @@ body.light-mode .title-bar {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Settings Dialog */
|
||||
.settings-dialog {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
z-index: 2000;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.settings-dialog.show {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.settings-content {
|
||||
background-color: var(--secondary-bg);
|
||||
border-radius: 16px;
|
||||
width: 500px;
|
||||
max-width: 90%;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
overflow: hidden;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
transform: translateY(-20px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.settings-header {
|
||||
background-color: var(--primary);
|
||||
padding: 20px 24px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.settings-header h2 {
|
||||
margin: 0;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.settings-close {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--text-primary);
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.settings-close:hover {
|
||||
background-color: var(--error);
|
||||
}
|
||||
|
||||
.settings-body {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.settings-section h3 {
|
||||
margin: 0 0 16px 0;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.theme-selector {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.theme-option {
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.theme-option input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.theme-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 16px;
|
||||
background-color: var(--background);
|
||||
border: 2px solid var(--border-color);
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.theme-option input[type="radio"]:checked + .theme-label {
|
||||
border-color: var(--accent);
|
||||
background-color: var(--secondary-bg-hover);
|
||||
}
|
||||
|
||||
.theme-label:hover {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.theme-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
/* Adjust container for spacing */
|
||||
.container {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
/* Info icon styling */
|
||||
.info-icon {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
cursor: help;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-icon img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.3s ease;
|
||||
filter: brightness(0) saturate(100%) invert(73%) sepia(11%) saturate(374%) hue-rotate(185deg) brightness(90%) contrast(87%);
|
||||
}
|
||||
|
||||
body.light-mode .info-icon img {
|
||||
filter: brightness(0) saturate(100%) invert(39%) sepia(9%) saturate(505%) hue-rotate(175deg) brightness(92%) contrast(87%);
|
||||
}
|
||||
|
||||
.info-icon:hover img {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Tooltip styling */
|
||||
.info-icon[title] {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-icon[title]:hover::after {
|
||||
content: attr(title);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: calc(100% + 10px);
|
||||
transform: translateY(-50%);
|
||||
background-color: var(--primary);
|
||||
color: var(--text-primary);
|
||||
padding: 8px 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
text-transform: none;
|
||||
letter-spacing: normal;
|
||||
white-space: normal;
|
||||
width: 300px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
line-height: 1.4;
|
||||
animation: tooltipFadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
.info-icon[title]:hover::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
transform: translateY(-50%);
|
||||
border: 6px solid transparent;
|
||||
border-right-color: var(--primary);
|
||||
margin-left: -2px;
|
||||
z-index: 1001;
|
||||
pointer-events: none;
|
||||
animation: tooltipFadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes tooltipFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-50%) translateX(5px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(-50%) translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Alternative tooltip position for items near the right edge */
|
||||
.metadata-table tr:nth-last-child(-n+3) .info-icon[title]:hover::after {
|
||||
top: auto;
|
||||
bottom: 50%;
|
||||
left: auto;
|
||||
right: calc(100% + 10px);
|
||||
transform: translateY(50%);
|
||||
}
|
||||
|
||||
.metadata-table tr:nth-last-child(-n+3) .info-icon[title]:hover::before {
|
||||
left: auto;
|
||||
right: 100%;
|
||||
border-right-color: transparent;
|
||||
border-left-color: var(--primary);
|
||||
margin-left: 0;
|
||||
margin-right: -2px;
|
||||
}
|
||||
|
||||
/* Action Buttons */
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
@ -611,6 +612,10 @@ body.light-mode .title-bar {
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
letter-spacing: 0.5px;
|
||||
height: 48px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.report-btn:hover {
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren