163 lines
3.8 KiB
Vue
163 lines
3.8 KiB
Vue
<template>
|
||
<div class="contrastChecker">
|
||
<div class="input-section">
|
||
<label for="domain">Domain eingeben:</label>
|
||
<div class="row">
|
||
<input id="domain" v-model="domainInput" type="text" placeholder="z. B. example.com" />
|
||
<button :disabled="!isValidDomain" @click="loadDomain">Anzeigen</button>
|
||
</div>
|
||
<p v-if="domainInput && !isValidDomain" class="error">Ungültige Domain</p>
|
||
</div>
|
||
|
||
<iframe
|
||
v-if="iframeSrc"
|
||
:src="iframeSrc"
|
||
class="preview-frame"
|
||
sandbox="allow-same-origin allow-scripts"
|
||
></iframe>
|
||
|
||
<div class="color-buttons">
|
||
<button @click="pickColor('background')">Hintergrundfarbe wählen</button>
|
||
<button @click="pickColor('text')">Schriftfarbe wählen</button>
|
||
</div>
|
||
|
||
<div v-if="contrastRatio" class="result-box">
|
||
<p><strong>Kontrast:</strong> {{ contrastRatio.toFixed(2) }}</p>
|
||
<p><strong>WCAG Bewertung:</strong> {{ contrastLevel }}</p>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
|
||
<script setup>
|
||
|
||
const domainInput = ref('')
|
||
const iframeSrc = ref('')
|
||
const bgColor = ref(null)
|
||
const textColor = ref(null)
|
||
|
||
const domainRegex = /^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
|
||
const isValidDomain = computed(() => domainRegex.test(domainInput.value))
|
||
|
||
// Diese Funktionen hinzufügen
|
||
function hexToRgb(hex) {
|
||
if (!hex) return null
|
||
let c = hex.replace('#', '')
|
||
if (c.length === 3) {
|
||
c = c.split('').map((char) => char + char).join('')
|
||
}
|
||
const bigint = parseInt(c, 16)
|
||
return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255]
|
||
}
|
||
|
||
function luminance(r, g, b) {
|
||
const a = [r, g, b].map(v => {
|
||
v /= 255
|
||
return v <= 0.03928
|
||
? v / 12.92
|
||
: Math.pow((v + 0.055) / 1.055, 2.4)
|
||
})
|
||
return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2]
|
||
}
|
||
|
||
function getContrast(bgHex, fgHex) {
|
||
const bgRgb = hexToRgb(bgHex)
|
||
const fgRgb = hexToRgb(fgHex)
|
||
if (!bgRgb || !fgRgb) return null
|
||
const L1 = luminance(...bgRgb)
|
||
const L2 = luminance(...fgRgb)
|
||
return (Math.max(L1, L2) + 0.05) / (Math.min(L1, L2) + 0.05)
|
||
}
|
||
function loadDomain() {
|
||
iframeSrc.value = 'https://' + domainInput.value
|
||
}
|
||
|
||
function pickColor(type) {
|
||
const input = document.createElement('input')
|
||
input.type = 'color'
|
||
input.style.display = 'none'
|
||
input.addEventListener('input', () => {
|
||
if (type === 'background') bgColor.value = input.value
|
||
if (type === 'text') textColor.value = input.value
|
||
})
|
||
document.body.appendChild(input)
|
||
input.click()
|
||
input.remove()
|
||
}
|
||
|
||
const contrastRatio = computed(() => {
|
||
if (!bgColor.value || !textColor.value) return null
|
||
try {
|
||
return getContrast(bgColor.value, textColor.value)
|
||
} catch (e) {
|
||
return null
|
||
}
|
||
})
|
||
|
||
const contrastLevel = computed(() => {
|
||
if (!contrastRatio.value) return 'unbekannt'
|
||
const ratio = contrastRatio.value
|
||
if (ratio >= 7) return 'AAA'
|
||
if (ratio >= 4.5) return 'AA'
|
||
if (ratio >= 3) return 'A'
|
||
return 'nicht ausreichend'
|
||
})
|
||
</script>
|
||
|
||
<style lang="sass">
|
||
.contrastChecker
|
||
max-width: 1200px
|
||
margin: 10vh auto 3rem auto
|
||
padding: 2rem
|
||
|
||
|
||
.input-section
|
||
margin-bottom: 1rem
|
||
|
||
.row
|
||
display: flex
|
||
gap: 0.5rem
|
||
margin-top: 0.5rem
|
||
|
||
input[type="text"]
|
||
flex: 1
|
||
padding: 0.5rem
|
||
border: 1px solid #ccc
|
||
border-radius: 4px
|
||
|
||
button
|
||
padding: 0.5rem 1rem
|
||
border: none
|
||
background-color: #007acc
|
||
color: white
|
||
cursor: pointer
|
||
border-radius: 4px
|
||
|
||
button:disabled
|
||
background-color: #ccc
|
||
cursor: not-allowed
|
||
|
||
.error
|
||
color: red
|
||
font-size: 0.9rem
|
||
margin-top: 0.25rem
|
||
|
||
.preview-frame
|
||
width: 100%
|
||
height: 300px
|
||
border: 1px solid #ccc
|
||
margin-top: 1rem
|
||
|
||
.color-buttons
|
||
margin-top: 1rem
|
||
display: flex
|
||
gap: 1rem
|
||
|
||
.result-box
|
||
margin-top: 1rem
|
||
padding: 1rem
|
||
border: 1px solid #ccc
|
||
border-radius: 4px
|
||
background: #f9f9f9
|
||
|
||
</style> |