mirror of
https://github.com/anotherhadi/blog.git
synced 2026-05-20 05:32:32 +02:00
1025d5bfa1
Signed-off-by: Hadi <hadi@example.com>
116 lines
3.7 KiB
Plaintext
116 lines
3.7 KiB
Plaintext
---
|
||
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>
|