🎮 Add tournament detail component for displaying Challonge tournament information
This commit is contained in:
@@ -0,0 +1,217 @@
|
|||||||
|
<!--
|
||||||
|
TournamentDetail Component
|
||||||
|
|
||||||
|
Displays detailed tournament information in an expandable section.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
- Expandable/collapsible details view
|
||||||
|
- JSON display of full tournament data
|
||||||
|
- Loading state for detail fetching
|
||||||
|
- Error handling
|
||||||
|
- Formatted JSON output
|
||||||
|
|
||||||
|
Props:
|
||||||
|
- tournamentDetails: Object containing full tournament data
|
||||||
|
- loading: Boolean for loading state
|
||||||
|
- error: String for error message
|
||||||
|
- isExpanded: Boolean to control visibility
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
<TournamentDetail
|
||||||
|
:tournament-details="details"
|
||||||
|
:loading="loading"
|
||||||
|
:error="error"
|
||||||
|
:is-expanded="true"
|
||||||
|
/>
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div v-if="isExpanded" class="tournament-detail">
|
||||||
|
<!-- Loading State -->
|
||||||
|
<div v-if="loading" class="detail-status loading">
|
||||||
|
<div class="spinner"></div>
|
||||||
|
<span>Loading tournament details...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Error State -->
|
||||||
|
<div v-else-if="error" class="detail-status error">
|
||||||
|
<span class="error-icon">⚠️</span>
|
||||||
|
<span>{{ error }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Details Content -->
|
||||||
|
<div v-else-if="tournamentDetails" class="detail-content">
|
||||||
|
<div class="detail-header">
|
||||||
|
<h4>Full Tournament Details</h4>
|
||||||
|
</div>
|
||||||
|
<pre class="detail-json">{{ formattedDetails }}</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Empty State (details expanded but no data) -->
|
||||||
|
<div v-else class="detail-status empty">
|
||||||
|
<span>No details available</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for TournamentDetail component
|
||||||
|
*/
|
||||||
|
const props = defineProps({
|
||||||
|
tournamentDetails: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
isExpanded: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format tournament details as pretty-printed JSON
|
||||||
|
*/
|
||||||
|
const formattedDetails = computed(() => {
|
||||||
|
if (!props.tournamentDetails) return '';
|
||||||
|
return JSON.stringify(props.tournamentDetails, null, 2);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tournament-detail {
|
||||||
|
margin-top: 1rem;
|
||||||
|
border-top: 2px solid #e0e0e0;
|
||||||
|
padding-top: 1rem;
|
||||||
|
animation: slideDown 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideDown {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-status {
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-status.loading {
|
||||||
|
background: #e3f2fd;
|
||||||
|
color: #1976d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-status.error {
|
||||||
|
background: #ffebee;
|
||||||
|
color: #c62828;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-status.empty {
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #666;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: 2px solid #1976d2;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-icon {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-content {
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-header {
|
||||||
|
background: #667eea;
|
||||||
|
color: white;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-header h4 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-json {
|
||||||
|
margin: 0;
|
||||||
|
padding: 1rem;
|
||||||
|
background: #282c34;
|
||||||
|
color: #abb2bf;
|
||||||
|
font-family: 'Fira Code', 'Monaco', 'Menlo', monospace;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
overflow-x: auto;
|
||||||
|
max-height: 600px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* JSON Syntax Highlighting (approximate) */
|
||||||
|
.detail-json {
|
||||||
|
/* Numbers */
|
||||||
|
background: linear-gradient(to bottom, #282c34 0%, #282c34 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scrollbar styling for detail-json */
|
||||||
|
.detail-json::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-json::-webkit-scrollbar-track {
|
||||||
|
background: #1e2127;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-json::-webkit-scrollbar-thumb {
|
||||||
|
background: #4b5362;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-json::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #5c6370;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive adjustments */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.detail-json {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
max-height: 400px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user