Skip to content

Commit

Permalink
Merge pull request #85 from plastic-labs/vince/folder-view-updates
Browse files Browse the repository at this point in the history
updating the folder view to be more delightful
  • Loading branch information
vintrocode authored Dec 17, 2024
2 parents 2fb48b1 + b9b23a1 commit 62687a1
Show file tree
Hide file tree
Showing 3 changed files with 259 additions and 32 deletions.
44 changes: 14 additions & 30 deletions quartz/components/PageList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,35 +40,23 @@ export const PageList: QuartzComponent = ({ cfg, fileData, allFiles, limit }: Pr
{list.map((page) => {
const title = page.frontmatter?.title
const tags = page.frontmatter?.tags ?? []
const tagsStr = JSON.stringify(tags)
const href = resolveRelative(fileData.slug!, page.slug!)

return (
<li class="section-li">
<div class="section">
{page.dates && (
<p class="meta">
<Date date={getDate(cfg, page)!} locale={cfg.locale} />
</p>
)}
<div class="desc">
<h3>
<a href={resolveRelative(fileData.slug!, page.slug!)} class="internal">
{title}
</a>
</h3>
<li class="section-li" data-tags={tagsStr}>
<a href={href} class="section-link">
<div class="section">
{page.dates && (
<p class="meta">
<Date date={getDate(cfg, page)!} locale={cfg.locale} />
</p>
)}
<div class="desc">
<h3>{title}</h3>
</div>
</div>
<ul class="tags">
{tags.map((tag) => (
<li>
<a
class="internal tag-link"
href={resolveRelative(fileData.slug!, `tags/${tag}` as FullSlug)}
>
{tag}
</a>
</li>
))}
</ul>
</div>
</a>
</li>
)
})}
Expand All @@ -80,8 +68,4 @@ PageList.css = `
.section h3 {
margin: 0;
}
.section > .tags {
margin: 0;
}
`
103 changes: 101 additions & 2 deletions quartz/components/pages/FolderContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,17 @@ export default ((opts?: Partial<FolderContentOptions>) => {
const isDirectChild = fileParts.length === folderParts.length + 1
return prefixed && isDirectChild
})

// Get all unique tags
const allTags = new Set<string>()
allPagesInFolder.forEach(file => {
const tags = file.frontmatter?.tags ?? []
tags.forEach(tag => allTags.add(tag))
})
const sortedTags = Array.from(allTags).sort()

const cssClasses: string[] = fileData.frontmatter?.cssclasses ?? []
const classes = ["popover-hint", ...cssClasses].join(" ")
const classes = ["popover-hint", "disable-card-preview", ...cssClasses].join(" ")
const listProps = {
...props,
allFiles: allPagesInFolder,
Expand All @@ -45,14 +54,103 @@ export default ((opts?: Partial<FolderContentOptions>) => {
? fileData.description
: htmlToJsx(fileData.filePath!, tree)

// Add client-side filtering script
const filterScript = `
let isInitialized = false;
function initializeTagFiltering() {
// Prevent double initialization
if (isInitialized) {
return;
}
const selectedTags = new Set()
const cards = document.querySelectorAll('.section-li')
const countEl = document.querySelector('.folder-count')
const tagButtons = document.querySelectorAll('.tag-filter-btn')
if (!cards.length || !tagButtons.length) {
return; // Don't initialize if elements aren't present
}
isInitialized = true;
function updateVisibility() {
let visibleCount = 0
cards.forEach(card => {
try {
const tagsAttr = card.getAttribute('data-tags')
const tags = JSON.parse(tagsAttr || '[]')
const shouldShow = selectedTags.size === 0 ||
tags.some(tag => selectedTags.has(tag))
card.style.display = shouldShow ? '' : 'none'
if (shouldShow) visibleCount++
} catch (e) {
console.error('Error processing card:', e)
}
})
if (countEl) {
const countText = ${JSON.stringify(i18n(cfg.locale).pages.folderContent.itemsUnderFolder({count: 0}))}
countEl.textContent = countText.replace('0', visibleCount.toString())
}
}
tagButtons.forEach(btn => {
// Remove any existing listeners first
const newBtn = btn.cloneNode(true)
btn.parentNode.replaceChild(newBtn, btn)
newBtn.addEventListener('click', () => {
const tag = newBtn.getAttribute('data-tag')
if (selectedTags.has(tag)) {
selectedTags.delete(tag)
newBtn.classList.remove('selected')
} else {
selectedTags.add(tag)
newBtn.classList.add('selected')
}
updateVisibility()
})
})
}
// Initialize on first load
initializeTagFiltering()
// Handle client-side navigation
document.addEventListener('nav', () => {
isInitialized = false;
setTimeout(initializeTagFiltering, 0)
})
// Backup initialization for edge cases
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeTagFiltering)
} else {
setTimeout(initializeTagFiltering, 0)
}
`

return (
<div class={classes}>
<article>
<p>{content}</p>
</article>
<div class="page-listing">
<div class="tag-filter">
{sortedTags.map(tag => (
<button
data-tag={tag}
class="tag-filter-btn"
type="button"
>
{tag}
</button>
))}
</div>
{options.showFolderCount && (
<p>
<p class="folder-count">
{i18n(cfg.locale).pages.folderContent.itemsUnderFolder({
count: allPagesInFolder.length,
})}
Expand All @@ -62,6 +160,7 @@ export default ((opts?: Partial<FolderContentOptions>) => {
<PageList {...listProps} />
</div>
</div>
<script dangerouslySetInnerHTML={{ __html: filterScript }} />
</div>
)
}
Expand Down
144 changes: 144 additions & 0 deletions quartz/styles/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -545,3 +545,147 @@ input {
padding: 0.5rem;
}

// Blog listing styles
.page-listing {
margin-top: 2rem;

.tag-filter {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 2rem;

.tag-filter-btn {
padding: 0.4rem 0.8rem;
border-radius: 20px;
border: 1px solid var(--lightgray);
background: var(--light);
color: var(--gray);
font-size: 0.9rem;
font-family: var(--bodyFont);
cursor: pointer;
transition: all 0.2s ease;

&:hover {
border-color: var(--secondary);
color: var(--tertiary);
background-color: var(--highlight);
}

&.selected {
background: var(--secondary);
color: var(--light);
border-color: var(--secondary);
}

&::before {
content: "#";
opacity: 0.7;
margin-right: 0.2rem;
}
}
}

.section-ul {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
margin-top: 1.5rem;
}

.section-li {
margin: 0;
transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
border-radius: 12px;
background: var(--light);
border: 1px solid var(--lightgray);
overflow: hidden;
position: relative;

.section-link {
text-decoration: none;
color: var(--darkgray);
background: none !important;
display: block;
height: 100%;

&:hover {
background: none !important;
color: var(--darkgray);
}
}

&:hover {
transform: translateY(-3px);
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
background-color: var(--highlight);

.section {
.desc {
h3 {
color: var(--tertiary);
}
}
}
}

.section {
display: flex;
flex-direction: column;
height: 100%;
padding: 1.25rem;
gap: 0.7rem;

.meta {
order: -1;
font-size: 0.9rem;
color: var(--gray);
}

.desc {
flex: 1;

h3 {
margin: 0;
font-size: 1.3rem;
line-height: 1.4;
transition: color 0.2s ease;
color: var(--secondary);
}
}
}

.internal {
&[href*=".html"],
&:not([href*="."]) {
&::before, &::after {
display: none !important;
}
}

// Keep the hover effect
&:hover {
color: var(--tertiary);
}
}
}
}

// Hide tags in tag page cards
[data-slug^="tags/"] .section-li .section .tags {
display: none;
}

// Disable preview popups for folder listing cards
.disable-card-preview {
.popover {
display: none !important;
}

.internal {
&::before, &::after {
display: none !important;
}
}
}

0 comments on commit 62687a1

Please sign in to comment.