mirror of
https://github.com/anotherhadi/blog.git
synced 2026-05-20 05:32:32 +02:00
@@ -0,0 +1,115 @@
|
||||
---
|
||||
import { getCategory, extractInlineHashtags } from "../utils/notes";
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
|
||||
interface Props {
|
||||
notes: CollectionEntry<"notes">[];
|
||||
currentEntry: CollectionEntry<"notes">;
|
||||
categories: string[];
|
||||
}
|
||||
|
||||
const { notes, currentEntry, categories } = Astro.props;
|
||||
---
|
||||
|
||||
<style>
|
||||
/*
|
||||
* DaisyUI's menu items use display:grid with grid-auto-columns:minmax(auto,max-content)
|
||||
* which expands to fit content. Override to block so text-overflow:ellipsis works directly.
|
||||
* Inner <ul> has no w-full so DaisyUI's margin-inline-start/padding-inline-start don't overflow.
|
||||
*/
|
||||
.nav-item {
|
||||
display: block !important;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<aside
|
||||
class="w-56 flex flex-col border-r border-base-300/60 h-[calc(100vh-3rem)]"
|
||||
style="background: oklch(4% 0 0);"
|
||||
>
|
||||
<div class="px-3 py-3 border-b border-base-300/40">
|
||||
<label
|
||||
class="input input-sm w-full font-mono text-xs border-base-300/40 bg-base-200/50"
|
||||
>
|
||||
<span class="text-base-content/30">›</span>
|
||||
<input
|
||||
data-search
|
||||
type="text"
|
||||
placeholder="search..."
|
||||
class="text-base-content/70 placeholder:text-base-content/25"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<ul
|
||||
class="nav-sidebar menu menu-xs flex-1 min-h-0 overflow-y-auto overflow-x-hidden px-2 py-2 bg-transparent"
|
||||
>
|
||||
{
|
||||
categories.map((cat) => (
|
||||
<li class="w-full">
|
||||
<details open={cat === getCategory(currentEntry)}>
|
||||
<summary class="font-bold tracking-tight text-sm">
|
||||
<span class="text-primary/50 font-mono">/</span>
|
||||
{cat}
|
||||
</summary>
|
||||
<ul>
|
||||
{notes
|
||||
.filter((n) => getCategory(n) === cat)
|
||||
.map((n) => (
|
||||
<li>
|
||||
<a
|
||||
href={`/notes/${n.id}`}
|
||||
class:list={[
|
||||
"nav-item font-mono text-xs tooltip tooltip-right",
|
||||
n.id === currentEntry.id ? "active" : "",
|
||||
]}
|
||||
data-tip={n.data.title}
|
||||
data-title={n.data.title.toLowerCase()}
|
||||
data-tags={[
|
||||
...n.data.tags,
|
||||
...extractInlineHashtags(n.body ?? ""),
|
||||
].join(",")}
|
||||
>
|
||||
{n.data.title}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
<script>
|
||||
document.addEventListener("astro:page-load", () => {
|
||||
const navItems = document.querySelectorAll<HTMLElement>(".nav-item");
|
||||
document
|
||||
.querySelectorAll<HTMLInputElement>("[data-search]")
|
||||
.forEach((input) => {
|
||||
input.addEventListener("input", (e) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
const raw = target.value.toLowerCase().trim();
|
||||
document
|
||||
.querySelectorAll<HTMLInputElement>("[data-search]")
|
||||
.forEach((o) => {
|
||||
if (o !== target) o.value = target.value;
|
||||
});
|
||||
const isTag = raw.startsWith("#");
|
||||
const search = isTag ? raw.slice(1) : raw;
|
||||
navItems.forEach((item) => {
|
||||
const title = item.dataset.title ?? "";
|
||||
const tags = item.dataset.tags ? item.dataset.tags.split(",") : [];
|
||||
const match =
|
||||
!search ||
|
||||
(isTag
|
||||
? tags.some((t) => t.includes(search))
|
||||
: title.includes(search) || tags.join(",").includes(search));
|
||||
item.style.display = match ? "" : "none";
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user