vue-button-symphony / index.html
drokid's picture
vue 3 framework demonstrator for simple hierarchy of buttons
d5dbda2 verified
Raw
History Blame Contribute Delete
11.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Button Symphony</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://unpkg.com/feather-icons"></script>
<style>
.btn-pulse:hover {
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
transform: translateY(20px);
}
</style>
</head>
<body class="bg-gradient-to-br from-indigo-50 to-purple-50 min-h-screen">
<div id="app" class="container mx-auto px-4 py-12">
<div class="text-center mb-16">
<h1 class="text-5xl font-bold text-indigo-800 mb-4">Vue Button Symphony</h1>
<p class="text-xl text-indigo-600 max-w-2xl mx-auto">
A playful demonstration of Vue 3's reactivity with a hierarchical button system
</p>
</div>
<div class="flex justify-center mb-12">
<button @click="resetAll" class="px-6 py-3 bg-gradient-to-r from-indigo-500 to-purple-600 text-white rounded-full shadow-lg hover:shadow-xl transition-all duration-300 flex items-center">
<i data-feather="refresh-cw" class="mr-2"></i>
Reset Symphony
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div v-for="(buttonGroup, index) in buttonGroups" :key="index"
class="bg-white p-6 rounded-2xl shadow-md hover:shadow-lg transition-all duration-300">
<div class="flex items-center justify-between mb-4">
<h2 class="text-2xl font-semibold text-indigo-700">{{ buttonGroup.name }}</h2>
<button @click="buttonGroup.showChildren = !buttonGroup.showChildren"
class="p-2 rounded-full hover:bg-indigo-50 transition-colors">
<i :data-feather="buttonGroup.showChildren ? 'chevron-up' : 'chevron-down'"></i>
</button>
</div>
<button @click="toggleButton(buttonGroup)"
:class="['w-full py-3 px-4 rounded-lg mb-4 transition-all duration-300 btn-pulse',
buttonGroup.active ? 'bg-indigo-600 text-white' : 'bg-indigo-100 text-indigo-800']">
{{ buttonGroup.active ? 'Active' : 'Activate' }} {{ buttonGroup.name }}
</button>
<transition-group name="v">
<div v-if="buttonGroup.showChildren" class="space-y-3 mt-3 pl-4 border-l-2 border-indigo-200">
<div v-for="(child, childIndex) in buttonGroup.children" :key="childIndex"
class="bg-indigo-50 p-3 rounded-lg">
<button @click="toggleNestedButton(buttonGroup, child)"
:class="['w-full py-2 px-3 rounded-md transition-all',
child.active ? 'bg-purple-600 text-white' : 'bg-purple-100 text-purple-800']">
{{ child.active ? '✓ ' : '' }}{{ child.name }}
</button>
<transition-group name="v" v-if="child.showGrandchildren">
<div v-for="(grandchild, gIndex) in child.grandchildren" :key="gIndex"
class="mt-2 ml-4 pl-2 border-l-2 border-purple-200">
<button @click="toggleGrandchildButton(buttonGroup, child, grandchild)"
:class="['w-full py-1 px-2 rounded text-sm transition-all',
grandchild.active ? 'bg-pink-600 text-white' : 'bg-pink-100 text-pink-800']">
{{ grandchild.active ? '✓ ' : '' }}{{ grandchild.name }}
</button>
</div>
</transition-group>
<button v-if="child.grandchildren.length > 0"
@click="child.showGrandchildren = !child.showGrandchildren"
class="mt-2 text-xs text-purple-500 hover:text-purple-700 flex items-center">
<i :data-feather="child.showGrandchildren ? 'minus' : 'plus'" class="w-3 h-3 mr-1"></i>
{{ child.showGrandchildren ? 'Hide' : 'Show' }} details
</button>
</div>
</div>
</transition-group>
</div>
</div>
<div class="mt-16 bg-white p-6 rounded-2xl shadow-md max-w-2xl mx-auto">
<h2 class="text-2xl font-semibold text-indigo-700 mb-4">Symphony Log</h2>
<div class="bg-indigo-50 p-4 rounded-lg max-h-64 overflow-y-auto">
<div v-for="(log, index) in logs" :key="index"
class="py-2 border-b border-indigo-100 last:border-0">
<p class="text-indigo-800">{{ log }}</p>
</div>
<p v-if="logs.length === 0" class="text-indigo-400 italic">No activity yet...</p>
</div>
</div>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const buttonGroups = ref([
{
name: 'Melody',
active: false,
showChildren: true,
children: [
{
name: 'Piano',
active: false,
showGrandchildren: false,
grandchildren: [
{ name: 'C Major', active: false },
{ name: 'A Minor', active: false },
{ name: 'G Dominant', active: false }
]
},
{
name: 'Violin',
active: false,
showGrandchildren: false,
grandchildren: [
{ name: 'Legato', active: false },
{ name: 'Staccato', active: false }
]
}
]
},
{
name: 'Harmony',
active: false,
showChildren: true,
children: [
{
name: 'Chords',
active: false,
showGrandchildren: false,
grandchildren: [
{ name: 'Triad', active: false },
{ name: 'Seventh', active: false },
{ name: 'Ninth', active: false }
]
},
{
name: 'Progressions',
active: false,
showGrandchildren: false,
grandchildren: [
{ name: 'I-IV-V', active: false },
{ name: 'ii-V-I', active: false }
]
}
]
},
{
name: 'Rhythm',
active: false,
showChildren: true,
children: [
{
name: 'Drums',
active: false,
showGrandchildren: false,
grandchildren: [
{ name: '4/4 Time', active: false },
{ name: '3/4 Time', active: false }
]
},
{
name: 'Percussion',
active: false,
showGrandchildren: false,
grandchildren: [
{ name: 'Tambourine', active: false },
{ name: 'Maracas', active: false }
]
}
]
}
]);
const logs = ref([]);
const toggleButton = (group) => {
group.active = !group.active;
addLog(`${group.name} ${group.active ? 'activated' : 'deactivated'}`);
};
const toggleNestedButton = (group, child) => {
child.active = !child.active;
addLog(`${child.name} in ${group.name} ${child.active ? 'activated' : 'deactivated'}`);
};
const toggleGrandchildButton = (group, child, grandchild) => {
grandchild.active = !grandchild.active;
addLog(`${grandchild.name} in ${child.name} (${group.name}) ${grandchild.active ? 'activated' : 'deactivated'}`);
};
const resetAll = () => {
buttonGroups.value.forEach(group => {
group.active = false;
group.children.forEach(child => {
child.active = false;
child.grandchildren.forEach(grandchild => {
grandchild.active = false;
});
});
});
addLog('Reset all buttons');
};
const addLog = (message) => {
const now = new Date();
const timestamp = now.toLocaleTimeString();
logs.value.unshift(`[${timestamp}] ${message}`);
if (logs.value.length > 20) {
logs.value.pop();
}
};
return {
buttonGroups,
logs,
toggleButton,
toggleNestedButton,
toggleGrandchildButton,
resetAll
};
},
mounted() {
feather.replace();
},
updated() {
feather.replace();
}
}).mount('#app');
</script>
</body>
</html>