feat(brand): AirCard-IOS – neues Logo und Name
- Name AirCard-IOS in Kopfzeile, Titel, Meta-Angaben (theme-color, apple-mobile-web-app-title) und README - Website-Icon: neues Logo als favicon.svg, favicon-32.png und deckendes apple-touch-icon.png (180 x 180, ohne Rundung) - Kopfzeile zeigt das Logo (28 px, auf schmalen Schirmen 24 px) vor dem Namen - Karten-Marken neu aus dem Logo abgeleitet (einfarbig, currentColor): Symbol mit drei gestaffelten Karten und ausgeschnittenen Wellen, Text als Pfade (Nunito Sans 800); IDs unverändert - Tests: Labels, Marken-Aufbau, Favicon, Icon-Dateien, index.html Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
94f6d74249
commit
d64c14eae1
11 files changed
+143
-16
No files matched your search
@@ -0,0 +1,49 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import indexHtml from '../index.html?raw';
|
||||
|
||||
const publicFile = (name: string) => readFileSync(resolve(import.meta.dirname, '../public', name));
|
||||
|
||||
/** Breite, Höhe und Farbtyp aus dem IHDR-Block eines PNG (Farbtyp 2 = RGB ohne Alphakanal, 6 = RGBA). */
|
||||
function pngInfo(buf: Buffer) {
|
||||
expect(buf.subarray(0, 8).toString('hex')).toBe('89504e470d0a1a0a');
|
||||
expect(buf.subarray(12, 16).toString('ascii')).toBe('IHDR');
|
||||
return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20), colorType: buf[25] };
|
||||
}
|
||||
|
||||
describe('Name und Kopfbereich', () => {
|
||||
it('Titel und Meta-Angaben nennen AirCard-IOS', () => {
|
||||
expect(indexHtml).toContain('<title>AirCard-IOS – Kartenmotiv gestalten</title>');
|
||||
expect(indexHtml).toContain('<meta name="theme-color" content="#0F1828" />');
|
||||
expect(indexHtml).toContain('<meta name="apple-mobile-web-app-title" content="AirCard-IOS" />');
|
||||
});
|
||||
|
||||
it('Icon-Links: SVG, 32-px-PNG, Apple-Touch-Icon', () => {
|
||||
expect(indexHtml).toContain('<link rel="icon" href="/favicon.svg" type="image/svg+xml" />');
|
||||
expect(indexHtml).toContain('<link rel="icon" href="/favicon-32.png" sizes="32x32" type="image/png" />');
|
||||
expect(indexHtml).toContain('<link rel="apple-touch-icon" href="/apple-touch-icon.png" />');
|
||||
});
|
||||
|
||||
it('Kopfzeile: dekoratives Logo (28 x 28) links vom Namen, beides im Markenlink', () => {
|
||||
expect(indexHtml).toContain(
|
||||
'<a class="brand" href="/" data-link><img src="/favicon.svg" alt="" width="28" height="28" /><span>AirCard-IOS</span></a>',
|
||||
);
|
||||
});
|
||||
|
||||
it('Fußzeilen-Hinweis bleibt unverändert', () => {
|
||||
expect(indexHtml).toContain(
|
||||
'Inoffizielles Hobbyprojekt. Keine Verbindung zu Apple, Visa, Mastercard, UnionPay, American Express, JCB oder Discover. Alle Marken gehören ihren Inhabern.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Icon-Dateien', () => {
|
||||
it('favicon-32.png ist 32 x 32', () => {
|
||||
expect(pngInfo(publicFile('favicon-32.png'))).toMatchObject({ width: 32, height: 32 });
|
||||
});
|
||||
|
||||
it('apple-touch-icon.png ist 180 x 180 und deckend (RGB ohne Alphakanal, kein transparenter Rand)', () => {
|
||||
expect(pngInfo(publicFile('apple-touch-icon.png'))).toEqual({ width: 180, height: 180, colorType: 2 });
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user