* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 40px 20px;
color: #fff;
}
h1 {
margin-bottom: 40px;
font-size: 2.5em;
background: linear-gradient(135deg, #FE5A1D 0%, #ff8a5c 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.tree-container {
position: relative;
display: flex;
justify-content: center;
}
.tree {
display: flex;
flex-direction: column;
align-items: center;
gap: 60px;
}
.generation {
display: flex;
justify-content: center;
gap: 40px;
flex-wrap: wrap;
}
.member {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
transition: transform 0.3s ease;
}
.member:hover {
transform: translateY(-5px);
}
.member-card {
background: linear-gradient(135deg, #FE5A1D 0%, #ff7a3d 100%);
border-radius: 15px;
padding: 20px;
min-width: 180px;
text-align: center;
box-shadow: 0 8px 20px rgba(254, 90, 29, 0.3);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.member-card::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s ease;
}
.member:hover .member-card::before {
left: 100%;
}
.member:hover .member-card {
box-shadow: 0 12px 30px rgba(254, 90, 29, 0.5);
}
.avatar {
width: 80px;
height: 80px;
border-radius: 50%;
background: linear-gradient(135deg, #fff 0%, #f0f0f0 100%);
margin: 0 auto 15px;
display: flex;
align-items: center;
justify-content: center;
font-size: 2em;
color: #FE5A1D;
font-weight: bold;
border: 3px solid rgba(255, 255, 255, 0.3);
}
.name {
font-size: 1.1em;
font-weight: bold;
margin-bottom: 5px;
}
.role {
font-size: 0.85em;
opacity: 0.9;
}
.connector {
position: absolute;
background: linear-gradient(135deg, #FE5A1D 0%, #ff8a5c 100%);
z-index: -1;
}
.vertical-line {
width: 3px;
height: 40px;
top: -40px;
left: 50%;
transform: translateX(-50%);
}
.horizontal-line {
height: 3px;
top: -40px;
}
.info-panel {
position: fixed;
bottom: 20px;
right: 20px;
background: rgba(254, 90, 29, 0.95);
border-radius: 15px;
padding: 20px;
max-width: 300px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
transform: translateX(400px);
transition: transform 0.3s ease;
}
.info-panel.active {
transform: translateX(0);
}
.info-panel h3 {
margin-bottom: 10px;
font-size: 1.3em;
}
.info-panel p {
font-size: 0.9em;
line-height: 1.6;
opacity: 0.95;
}
.close-btn {
position: absolute;
top: 10px;
right: 10px;
background: rgba(255, 255, 255, 0.2);
border: none;
color: white;
width: 30px;
height: 30px;
border-radius: 50%;
cursor: pointer;
font-size: 1.2em;
transition: background 0.3s ease;
}
.close-btn:hover {
background: rgba(255, 255, 255, 0.3);
}
@media (max-width: 768px) {
h1 {
font-size: 1.8em;
}
.generation {
gap: 20px;
}
.member-card {
min-width: 140px;
padding: 15px;
}
.avatar {
width: 60px;
height: 60px;
font-size: 1.5em;
}
.info-panel {
bottom: 10px;
right: 10px;
left: 10px;
max-width: none;
}
}
const familyData = {
name: "Robert Smith",
role: "Grandfather",
born: "1945",
details: "Retired teacher, loves gardening and classical music.",
children: [
{
name: "Michael Smith",
role: "Father",
born: "1970",
details: "Software engineer with 20 years of experience.",
children: [
{
name: "Sarah Smith",
role: "Daughter",
born: "1998",
details: "Medical student passionate about pediatrics."
},
{
name: "James Smith",
role: "Son",
born: "2000",
details: "Computer science major, loves game development."
}
]
},
{
name: "Jennifer Smith",
role: "Aunt",
born: "1972",
details: "Architect and interior designer.",
children: [
{
name: "Emma Johnson",
role: "Cousin",
born: "2002",
details: "Art student specializing in digital media."
}
]
}
]
};
function getInitials(name) {
return name.split(' ').map(n => n[0]).join('');
}
function createMember(person, level) {
const member = document.createElement('div');
member.className = 'member';
const card = document.createElement('div');
card.className = 'member-card';
const avatar = document.createElement('div');
avatar.className = 'avatar';
avatar.textContent = getInitials(person.name);
const name = document.createElement('div');
name.className = 'name';
name.textContent = person.name;
const role = document.createElement('div');
role.className = 'role';
role.textContent = person.role;
card.appendChild(avatar);
card.appendChild(name);
card.appendChild(role);
member.appendChild(card);
if (level > 0) {
const line = document.createElement('div');
line.className = 'connector vertical-line';
member.appendChild(line);
}
member.addEventListener('click', () => showInfo(person));
return member;
}
function buildTree(data, container, level = 0) {
const generation = document.createElement('div');
generation.className = 'generation';
const member = createMember(data, level);
generation.appendChild(member);
container.appendChild(generation);
if (data.children && data.children.length > 0) {
const childGeneration = document.createElement('div');
childGeneration.className = 'generation';
data.children.forEach(child => {
const childMember = createMember(child, level + 1);
childGeneration.appendChild(childMember);
if (child.children && child.children.length > 0) {
const subTree = document.createElement('div');
subTree.className = 'tree';
child.children.forEach(grandchild => {
const grandchildGen = document.createElement('div');
grandchildGen.className = 'generation';
const grandchildMember = createMember(grandchild, level + 2);
grandchildGen.appendChild(grandchildMember);
subTree.appendChild(grandchildGen);
});
container.appendChild(subTree);
}
});
container.appendChild(childGeneration);
}
}
function showInfo(person) {
const panel = document.getElementById('infoPanel');
const nameEl = document.getElementById('infoName');
const detailsEl = document.getElementById('infoDetails');
nameEl.textContent = person.name;
detailsEl.innerHTML = `
<strong>Role:</strong> ${person.role}<br>
<strong>Born:</strong> ${person.born}<br><br>
${person.details}
`;
panel.classList.add('active');
}
function closeInfo() {
document.getElementById('infoPanel').classList.remove('active');
}
const treeContainer = document.getElementById('familyTree');
buildTree(familyData, treeContainer);
No comments yet. Be the first!