feat(home): explore page
This commit is contained in:
parent
73878b421d
commit
3772295a07
3 changed files with 431 additions and 157 deletions
327
index.html
327
index.html
|
|
@ -2151,166 +2151,20 @@
|
|||
</header>
|
||||
|
||||
<div id="page-home" class="page">
|
||||
<div id="home-welcome" style="display: none; text-align: center; padding: 4rem 2rem">
|
||||
<h2 style="margin-bottom: 1rem">Welcome to Monochrome</h2>
|
||||
<p style="color: var(--muted-foreground)">
|
||||
You haven't listened to anything yet. Search for your favorite songs to get started!
|
||||
</p>
|
||||
<div class="home-header-tabs">
|
||||
<button class="home-tab active" data-tab="for-you">Home</button>
|
||||
<button class="home-tab" data-tab="explore">Hot & New</button>
|
||||
</div>
|
||||
|
||||
<section class="content-section" id="home-editors-picks-section-empty" style="margin-top: 0">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Editor's Picks</h2>
|
||||
<div id="home-view-for-you" class="home-view active">
|
||||
<div id="home-welcome" style="display: none; text-align: center; padding: 4rem 2rem">
|
||||
<h2 style="margin-bottom: 1rem">Welcome to Monochrome</h2>
|
||||
<p style="color: var(--muted-foreground)">
|
||||
You haven't listened to anything yet. Search for your favorite songs to get started!
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-grid" id="home-editors-picks-empty"></div>
|
||||
</section>
|
||||
|
||||
<div id="home-content" style="display: none">
|
||||
<section class="content-section">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Recommended Songs</h2>
|
||||
<button
|
||||
class="btn-secondary"
|
||||
id="refresh-songs-btn"
|
||||
title="Refresh"
|
||||
style="padding: 4px 8px"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="track-list" id="home-recommended-songs"></div>
|
||||
</section>
|
||||
<section class="content-section">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Recommended Albums</h2>
|
||||
<button
|
||||
class="btn-secondary"
|
||||
id="refresh-albums-btn"
|
||||
title="Refresh"
|
||||
style="padding: 4px 8px"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-grid" id="home-recommended-albums"></div>
|
||||
</section>
|
||||
<section class="content-section">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Recommended Artists</h2>
|
||||
<button
|
||||
class="btn-secondary"
|
||||
id="refresh-artists-btn"
|
||||
title="Refresh"
|
||||
style="padding: 4px 8px"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-grid" id="home-recommended-artists"></div>
|
||||
</section>
|
||||
<section class="content-section">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Jump Back In</h2>
|
||||
<button
|
||||
class="btn-secondary"
|
||||
id="clear-recent-btn"
|
||||
title="Clear History"
|
||||
style="padding: 4px 8px"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M3 6h18" />
|
||||
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
|
||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-grid" id="home-recent-mixed"></div>
|
||||
</section>
|
||||
<section class="content-section" id="home-editors-picks-section">
|
||||
<section class="content-section" id="home-editors-picks-section-empty" style="margin-top: 0">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
|
|
@ -2321,8 +2175,167 @@
|
|||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Editor's Picks</h2>
|
||||
</div>
|
||||
<div class="card-grid" id="home-editors-picks"></div>
|
||||
<div class="card-grid" id="home-editors-picks-empty"></div>
|
||||
</section>
|
||||
|
||||
<div id="home-content" style="display: none">
|
||||
<section class="content-section">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Recommended Songs</h2>
|
||||
<button
|
||||
class="btn-secondary"
|
||||
id="refresh-songs-btn"
|
||||
title="Refresh"
|
||||
style="padding: 4px 8px"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="track-list" id="home-recommended-songs"></div>
|
||||
</section>
|
||||
<section class="content-section">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Recommended Albums</h2>
|
||||
<button
|
||||
class="btn-secondary"
|
||||
id="refresh-albums-btn"
|
||||
title="Refresh"
|
||||
style="padding: 4px 8px"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-grid" id="home-recommended-albums"></div>
|
||||
</section>
|
||||
<section class="content-section">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Recommended Artists</h2>
|
||||
<button
|
||||
class="btn-secondary"
|
||||
id="refresh-artists-btn"
|
||||
title="Refresh"
|
||||
style="padding: 4px 8px"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
||||
<path d="M21 3v5h-5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-grid" id="home-recommended-artists"></div>
|
||||
</section>
|
||||
<section class="content-section">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Jump Back In</h2>
|
||||
<button
|
||||
class="btn-secondary"
|
||||
id="clear-recent-btn"
|
||||
title="Clear History"
|
||||
style="padding: 4px 8px"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M3 6h18" />
|
||||
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
|
||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-grid" id="home-recent-mixed"></div>
|
||||
</section>
|
||||
<section class="content-section" id="home-editors-picks-section">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: 0">Editor's Picks</h2>
|
||||
</div>
|
||||
<div class="card-grid" id="home-editors-picks"></div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="home-view-explore" class="home-view" style="display: none;">
|
||||
<div id="explore-content">
|
||||
<div class="card-grid" id="explore-grid"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
229
js/ui.js
229
js/ui.js
|
|
@ -1629,6 +1629,7 @@ export class UIRenderer {
|
|||
|
||||
try {
|
||||
this.showPage('home');
|
||||
this.setupHomeTabs();
|
||||
|
||||
const welcomeEl = document.getElementById('home-welcome');
|
||||
const contentEl = document.getElementById('home-content');
|
||||
|
|
@ -1698,6 +1699,234 @@ export class UIRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
setupHomeTabs() {
|
||||
const tabs = document.querySelectorAll('.home-tab');
|
||||
if (tabs.length === 0) return;
|
||||
|
||||
if (tabs[0].dataset.initialized) return;
|
||||
|
||||
tabs.forEach((tab) => {
|
||||
tab.dataset.initialized = 'true';
|
||||
tab.addEventListener('click', () => {
|
||||
document.querySelectorAll('.home-tab').forEach((t) => t.classList.remove('active'));
|
||||
document.querySelectorAll('.home-view').forEach((v) => {
|
||||
v.style.display = 'none';
|
||||
v.classList.remove('active');
|
||||
});
|
||||
|
||||
tab.classList.add('active');
|
||||
const viewId = `home-view-${tab.dataset.tab}`;
|
||||
const view = document.getElementById(viewId);
|
||||
if (view) {
|
||||
view.style.display = 'block';
|
||||
view.classList.add('active');
|
||||
}
|
||||
|
||||
if (tab.dataset.tab === 'explore') {
|
||||
this.renderExplorePage();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async renderExplorePage() {
|
||||
const container = document.getElementById('explore-grid');
|
||||
if (!container) return;
|
||||
|
||||
if (container.children.length > 0) return;
|
||||
|
||||
container.classList.remove('card-grid');
|
||||
|
||||
container.innerHTML = `<div class="card-grid">${this.createSkeletonCards(12)}</div>`;
|
||||
|
||||
try {
|
||||
const response = await fetch('https://hot.monochrome.tf/');
|
||||
if (!response.ok) throw new Error('Failed to load explore data');
|
||||
const data = await response.json();
|
||||
|
||||
container.innerHTML = '';
|
||||
|
||||
const GENRES = [
|
||||
{ id: 'hip_hop', name: 'Hip Hop / Rap' },
|
||||
{ id: 'pop', name: 'Pop' },
|
||||
{ id: 'rock', name: 'Rock' },
|
||||
{ id: 'electronic', name: 'Electronic' },
|
||||
{ id: 'country', name: 'Country' },
|
||||
{ id: 'jazz', name: 'Jazz' },
|
||||
{ id: 'classical', name: 'Classical' },
|
||||
{ id: 'latin', name: 'Latin' },
|
||||
{ id: 'reggae', name: 'Reggae / Dancehall' },
|
||||
{ id: 'blues', name: 'Blues' },
|
||||
{ id: 'soundtrack', name: 'Soundtrack' },
|
||||
{ id: 'alternative', name: 'Alternative' },
|
||||
];
|
||||
|
||||
if (GENRES.length > 0) {
|
||||
const genresSection = document.createElement('section');
|
||||
genresSection.className = 'content-section';
|
||||
genresSection.innerHTML = `<h2 class="section-title">Genres</h2>`;
|
||||
|
||||
const genresGrid = document.createElement('div');
|
||||
genresGrid.className = 'card-grid';
|
||||
genresGrid.innerHTML = GENRES
|
||||
.map(
|
||||
(genre) => `
|
||||
<div class="card genre-card" data-genre-id="${genre.id}" data-genre-name="${escapeHtml(genre.name)}" style="cursor: pointer; background: var(--secondary); padding: 1.5rem; display: flex; align-items: center; justify-content: center; text-align: center; min-height: 100px; border-radius: var(--radius); border: 1px solid var(--border);">
|
||||
<h3 style="margin: 0; font-size: 1.1rem; font-weight: 600;">${escapeHtml(genre.name)}</h3>
|
||||
</div>
|
||||
`
|
||||
)
|
||||
.join('');
|
||||
|
||||
genresSection.appendChild(genresGrid);
|
||||
container.appendChild(genresSection);
|
||||
|
||||
genresGrid.querySelectorAll('.genre-card').forEach((card) => {
|
||||
card.addEventListener('click', () => {
|
||||
this.renderGenrePage(card.dataset.genreId, card.dataset.genreName);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (data.top_albums && data.top_albums.length > 0) {
|
||||
this.renderExploreSection(container, 'Trending Albums', data.top_albums, 'album');
|
||||
}
|
||||
|
||||
if (data.top_tracks && data.top_tracks.length > 0) {
|
||||
this.renderExploreSection(container, 'Trending Tracks', data.top_tracks, 'track');
|
||||
}
|
||||
|
||||
if (data.featured_playlists && data.featured_playlists.length > 0) {
|
||||
this.renderExploreSection(container, 'Featured Playlists', data.featured_playlists, 'playlist');
|
||||
}
|
||||
|
||||
if (data.sections && data.sections.length > 0) {
|
||||
data.sections.forEach((section) => {
|
||||
if (section.items && section.items.length > 0) {
|
||||
let type = null;
|
||||
if (section.type === 'ALBUM_LIST') type = 'album';
|
||||
else if (section.type === 'TRACK_LIST') type = 'track';
|
||||
else if (section.type === 'PLAYLIST_LIST') type = 'playlist';
|
||||
|
||||
if (type) {
|
||||
this.renderExploreSection(container, section.title, section.items, type);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (container.children.length === 0) {
|
||||
container.innerHTML = createPlaceholder('No explore content available.');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
container.innerHTML = createPlaceholder('Failed to load explore content.');
|
||||
}
|
||||
}
|
||||
|
||||
renderExploreSection(container, title, items, type) {
|
||||
const section = document.createElement('section');
|
||||
section.className = 'content-section';
|
||||
section.innerHTML = `<h2 class="section-title">${title}</h2>`;
|
||||
|
||||
if (type === 'track') {
|
||||
const list = document.createElement('div');
|
||||
list.className = 'track-list';
|
||||
this.renderListWithTracks(list, items, true);
|
||||
section.appendChild(list);
|
||||
} else {
|
||||
const grid = document.createElement('div');
|
||||
grid.className = 'card-grid';
|
||||
grid.innerHTML = items
|
||||
.map((item) => {
|
||||
if (type === 'album') return this.createAlbumCardHTML(item);
|
||||
if (type === 'playlist') return this.createPlaylistCardHTML(item);
|
||||
return '';
|
||||
})
|
||||
.join('');
|
||||
|
||||
items.forEach((item) => {
|
||||
let selector;
|
||||
if (type === 'album') selector = `[data-album-id="${item.id}"]`;
|
||||
if (type === 'playlist') selector = `[data-playlist-id="${item.uuid}"]`;
|
||||
|
||||
if (selector) {
|
||||
const el = grid.querySelector(selector);
|
||||
if (el) {
|
||||
trackDataStore.set(el, item);
|
||||
if (type === 'album') this.updateLikeState(el, 'album', item.id);
|
||||
if (type === 'playlist') this.updateLikeState(el, 'playlist', item.uuid);
|
||||
}
|
||||
}
|
||||
});
|
||||
section.appendChild(grid);
|
||||
}
|
||||
container.appendChild(section);
|
||||
}
|
||||
|
||||
async renderGenrePage(genreId, genreName) {
|
||||
const container = document.getElementById('explore-grid');
|
||||
if (!container) return;
|
||||
|
||||
container.classList.remove('card-grid');
|
||||
|
||||
container.innerHTML = `
|
||||
<div style="margin-bottom: 1.5rem; display: flex; align-items: center; gap: 1rem;">
|
||||
<button class="btn-secondary explore-back-btn" style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
|
||||
Back
|
||||
</button>
|
||||
<h2 class="section-title" style="margin: 0;">${escapeHtml(genreName)}</h2>
|
||||
</div>
|
||||
<div class="card-grid">${this.createSkeletonCards(12)}</div>
|
||||
`;
|
||||
|
||||
container.querySelector('.explore-back-btn').addEventListener('click', () => {
|
||||
container.innerHTML = '';
|
||||
this.renderExplorePage();
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://hot.monochrome.tf/explore/genre/?id=${genreId}`);
|
||||
if (!response.ok) throw new Error('Failed to load genre data');
|
||||
const data = await response.json();
|
||||
|
||||
const header = container.firstElementChild;
|
||||
container.innerHTML = '';
|
||||
container.appendChild(header);
|
||||
|
||||
const contentContainer = document.createElement('div');
|
||||
container.appendChild(contentContainer);
|
||||
|
||||
if (data.sections && data.sections.length > 0) {
|
||||
data.sections.forEach((section) => {
|
||||
if (section.items && section.items.length > 0) {
|
||||
let type = null;
|
||||
if (section.type === 'ALBUM_LIST') type = 'album';
|
||||
else if (section.type === 'TRACK_LIST') type = 'track';
|
||||
else if (section.type === 'PLAYLIST_LIST') type = 'playlist';
|
||||
|
||||
if (type) {
|
||||
this.renderExploreSection(contentContainer, section.title, section.items, type);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (contentContainer.children.length === 0) {
|
||||
contentContainer.innerHTML = createPlaceholder('No content found for this genre.');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
const header = container.firstElementChild;
|
||||
container.innerHTML = '';
|
||||
container.appendChild(header);
|
||||
const errorDiv = document.createElement('div');
|
||||
errorDiv.innerHTML = createPlaceholder('Failed to load genre content.');
|
||||
container.appendChild(errorDiv);
|
||||
}
|
||||
}
|
||||
|
||||
async getSeeds() {
|
||||
const history = await db.getHistory();
|
||||
const favorites = await db.getFavorites('track');
|
||||
|
|
|
|||
32
styles.css
32
styles.css
|
|
@ -7835,3 +7835,35 @@ textarea:focus {
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.home-header-tabs {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.home-tab {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--muted-foreground);
|
||||
padding: 0.75rem 0.5rem;
|
||||
cursor: pointer;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: all var(--transition);
|
||||
}
|
||||
|
||||
.home-tab:hover {
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.home-tab.active {
|
||||
color: var(--foreground);
|
||||
border-bottom-color: var(--highlight);
|
||||
}
|
||||
|
||||
.home-view {
|
||||
animation: fade-in 0.3s ease;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue