|
|
import gradio as gr |
|
|
|
|
|
class DTCDisplay(gr.HTML): |
|
|
"""Custom component for displaying Diagnostic Trouble Codes as cards""" |
|
|
|
|
|
def __init__(self, value=None, **kwargs): |
|
|
html_template = """ |
|
|
<div class="dtc-main"> |
|
|
<h3 class="dtc-title">🔧 Diagnostic Trouble Codes</h3> |
|
|
<div class="dtc-wrapper"> |
|
|
${value && value.length > 0 ? ` |
|
|
<div class="dtc-container"> |
|
|
${value.map(dtc => { |
|
|
const firstLetter = dtc.code.charAt(0).toUpperCase(); |
|
|
let cardClass = 'dtc-card'; |
|
|
let icon = '⚠️'; |
|
|
|
|
|
if (firstLetter === 'P') { |
|
|
cardClass += ' dtc-powertrain'; |
|
|
icon = '⚙️'; |
|
|
} else if (firstLetter === 'C') { |
|
|
cardClass += ' dtc-chassis'; |
|
|
icon = '🚗'; |
|
|
} else if (firstLetter === 'B') { |
|
|
cardClass += ' dtc-body'; |
|
|
icon = '🔌'; |
|
|
} else if (firstLetter === 'U') { |
|
|
cardClass += ' dtc-network'; |
|
|
icon = '📡'; |
|
|
} |
|
|
|
|
|
return `<div class="${cardClass}"> |
|
|
<div class="dtc-header"> |
|
|
<div class="dtc-icon">${icon}</div> |
|
|
<div class="dtc-code">${dtc.code}</div> |
|
|
</div> |
|
|
<div class="dtc-description">${dtc.description}</div> |
|
|
</div>`; |
|
|
}).join('')} |
|
|
</div> |
|
|
` : ` |
|
|
<div class="dtc-empty">✓ No fault codes detected</div> |
|
|
`} |
|
|
</div> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
css_template = """ |
|
|
.dtc-main { |
|
|
width: 100%; |
|
|
} |
|
|
|
|
|
.dtc-title { |
|
|
margin: 0 0 12px 0; |
|
|
font-size: 18px; |
|
|
font-weight: 600; |
|
|
color: #333; |
|
|
} |
|
|
|
|
|
.dtc-wrapper { |
|
|
width: 100%; |
|
|
border: 1px solid #e0e0e0; |
|
|
border-radius: 8px; |
|
|
padding: 16px; |
|
|
} |
|
|
|
|
|
.dtc-container { |
|
|
display: flex; |
|
|
flex-wrap: wrap; |
|
|
gap: 16px; |
|
|
padding: 0; |
|
|
justify-content: center; |
|
|
} |
|
|
|
|
|
.dtc-card { |
|
|
border-radius: 8px; |
|
|
padding: 10px 12px; |
|
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12); |
|
|
min-width: 140px; |
|
|
max-width: 190px; |
|
|
flex: 1 1 auto; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
gap: 8px; |
|
|
transition: transform 0.2s ease, box-shadow 0.2s ease; |
|
|
} |
|
|
|
|
|
.dtc-card:hover { |
|
|
transform: translateY(-2px); |
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18); |
|
|
} |
|
|
|
|
|
/* Powertrain - Orange/Amber */ |
|
|
.dtc-powertrain { |
|
|
background: linear-gradient(135deg, #ffa726 0%, #ff9800 100%); |
|
|
} |
|
|
|
|
|
/* Chassis - Blue */ |
|
|
.dtc-chassis { |
|
|
background: linear-gradient(135deg, #42a5f5 0%, #2196f3 100%); |
|
|
} |
|
|
|
|
|
/* Body - Purple */ |
|
|
.dtc-body { |
|
|
background: linear-gradient(135deg, #ab47bc 0%, #9c27b0 100%); |
|
|
} |
|
|
|
|
|
/* Network - Green */ |
|
|
.dtc-network { |
|
|
background: linear-gradient(135deg, #66bb6a 0%, #4caf50 100%); |
|
|
} |
|
|
|
|
|
.dtc-header { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
gap: 8px; |
|
|
} |
|
|
|
|
|
.dtc-icon { |
|
|
font-size: 26px; |
|
|
filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.15)); |
|
|
} |
|
|
|
|
|
.dtc-code { |
|
|
font-size: 14px; |
|
|
font-weight: bold; |
|
|
color: white; |
|
|
font-family: 'Courier New', monospace; |
|
|
letter-spacing: 1px; |
|
|
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); |
|
|
} |
|
|
|
|
|
.dtc-description { |
|
|
font-size: 13px; |
|
|
color: rgba(255, 255, 255, 0.95); |
|
|
text-align: center; |
|
|
line-height: 1.4; |
|
|
} |
|
|
|
|
|
.dtc-empty { |
|
|
color: #4caf50; |
|
|
font-weight: 500; |
|
|
text-align: center; |
|
|
padding: 24px; |
|
|
font-size: 15px; |
|
|
} |
|
|
""" |
|
|
|
|
|
super().__init__( |
|
|
value=value or [], |
|
|
html_template=html_template, |
|
|
css_template=css_template, |
|
|
**kwargs |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|